From 0f8e8788d62e8248135fed6492b671d0e506e24a Mon Sep 17 00:00:00 2001 From: MK Date: Sun, 8 Mar 2026 19:35:39 +0800 Subject: [PATCH 1/2] chore: migrate to vp --- .github/FUNDING.yml | 1 + .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- .github/workflows/codeql-analysis.yml | 56 +- .github/workflows/gh-pages.yml | 36 +- .github/workflows/nodejs-3.x.yml | 12 +- .github/workflows/release.yml | 2 +- .vite-hooks/pre-commit | 1 + .vscode/extensions.json | 3 + .vscode/settings.json | 9 + AGENTS.md | 76 + CHANGELOG.md | 3052 ++++++++--------- CONTRIBUTING.md | 8 +- CONTRIBUTING.zh-CN.md | 12 +- History.md | 57 +- agent.js | 4 +- app/extend/context.js | 87 +- app/extend/helper.js | 14 +- app/extend/request.js | 49 +- app/extend/response.js | 25 +- app/middleware/body_parser.js | 4 +- app/middleware/meta.js | 17 +- app/middleware/notfound.js | 8 +- app/middleware/override_method.js | 4 +- app/middleware/site_file.js | 16 +- config/config.default.js | 90 +- config/config.local.js | 4 +- config/config.unittest.js | 4 +- config/plugin.js | 26 +- eslint.config.mjs | 25 - index.d.ts | 216 +- index.js | 22 +- index.test-d.ts | 2 +- lib/agent.js | 51 +- lib/application.js | 131 +- lib/core/base_context_class.js | 8 +- lib/core/base_context_logger.js | 12 +- lib/core/base_hook_class.js | 11 +- lib/core/context_httpclient.js | 4 +- lib/core/dnscache_httpclient.js | 23 +- lib/core/fetch_factory.js | 14 +- lib/core/httpclient.js | 36 +- lib/core/httpclient_next.js | 22 +- lib/core/logger.js | 14 +- lib/core/messenger/index.js | 16 +- lib/core/messenger/ipc.js | 46 +- lib/core/messenger/local.js | 41 +- lib/core/singleton.js | 57 +- lib/core/utils.js | 193 +- lib/egg.js | 187 +- lib/loader/agent_worker_loader.js | 5 +- lib/loader/app_worker_loader.js | 6 +- lib/loader/index.js | 8 +- lib/start.js | 15 +- package.json | 103 +- site/app.ts | 14 +- site/config/config.ts | 102 +- site/docs/advanced/cluster-client.md | 42 +- site/docs/advanced/cluster-client.zh-CN.md | 82 +- site/docs/advanced/framework.md | 76 +- site/docs/advanced/framework.zh-CN.md | 97 +- site/docs/advanced/loader-update.zh-CN.md | 2 - site/docs/advanced/loader.md | 65 +- site/docs/advanced/loader.zh-CN.md | 71 +- site/docs/advanced/plugin.md | 105 +- site/docs/advanced/plugin.zh-CN.md | 108 +- site/docs/advanced/view-plugin.md | 5 +- site/docs/advanced/view-plugin.zh-CN.md | 24 +- site/docs/basics/app-start.md | 10 +- site/docs/basics/app-start.zh-CN.md | 13 +- site/docs/basics/config.md | 14 +- site/docs/basics/config.zh-CN.md | 29 +- site/docs/basics/controller.md | 184 +- site/docs/basics/controller.zh-CN.md | 239 +- site/docs/basics/env.zh-CN.md | 13 +- site/docs/basics/extend.md | 14 +- site/docs/basics/extend.zh-CN.md | 24 +- site/docs/basics/middleware.md | 34 +- site/docs/basics/middleware.zh-CN.md | 48 +- site/docs/basics/objects.md | 16 +- site/docs/basics/objects.zh-CN.md | 24 +- site/docs/basics/plugin.md | 18 +- site/docs/basics/plugin.zh-CN.md | 26 +- site/docs/basics/router.md | 66 +- site/docs/basics/router.zh-CN.md | 75 +- site/docs/basics/schedule.md | 40 +- site/docs/basics/schedule.zh-CN.md | 44 +- site/docs/basics/service.md | 20 +- site/docs/basics/service.zh-CN.md | 27 +- site/docs/basics/structure.zh-CN.md | 1 - site/docs/community/CONTRIBUTING.zh-CN.md | 23 +- site/docs/community/faq.md | 8 +- site/docs/community/faq.zh-CN.md | 10 +- site/docs/community/style-guide.md | 12 +- site/docs/community/style-guide.zh-CN.md | 12 +- site/docs/core/cluster-and-ipc.md | 54 +- site/docs/core/cluster-and-ipc.zh-CN.md | 68 +- site/docs/core/cookie-and-session.md | 22 +- site/docs/core/cookie-and-session.zh-CN.md | 31 +- site/docs/core/deployment.md | 2 +- site/docs/core/deployment.zh-CN.md | 9 +- site/docs/core/development.md | 6 +- site/docs/core/development.zh-CN.md | 12 +- site/docs/core/error-handling.md | 16 +- site/docs/core/error-handling.zh-CN.md | 65 +- site/docs/core/httpclient.md | 132 +- site/docs/core/httpclient.zh-CN.md | 185 +- site/docs/core/i18n.md | 20 +- site/docs/core/i18n.zh-CN.md | 25 +- site/docs/core/logger.md | 86 +- site/docs/core/logger.zh-CN.md | 114 +- site/docs/core/security.md | 49 +- site/docs/core/security.zh-CN.md | 52 +- site/docs/core/unittest.md | 213 +- site/docs/core/unittest.zh-CN.md | 277 +- site/docs/core/view.md | 43 +- site/docs/core/view.zh-CN.md | 46 +- site/docs/intro/egg-and-koa.md | 10 +- site/docs/intro/egg-and-koa.zh-CN.md | 11 +- site/docs/intro/migration.md | 18 +- site/docs/intro/migration.zh-CN.md | 23 +- site/docs/intro/progressive.md | 8 +- site/docs/intro/progressive.zh-CN.md | 9 +- site/docs/intro/quickstart.md | 71 +- site/docs/intro/quickstart.zh-CN.md | 107 +- site/docs/tutorials/assets.zh-CN.md | 52 +- site/docs/tutorials/index.zh-CN.md | 4 +- site/docs/tutorials/mysql.md | 40 +- site/docs/tutorials/mysql.zh-CN.md | 102 +- site/docs/tutorials/passport.md | 35 +- site/docs/tutorials/passport.zh-CN.md | 85 +- site/docs/tutorials/proxy.md | 6 +- site/docs/tutorials/proxy.zh-CN.md | 6 +- site/docs/tutorials/restful.md | 104 +- site/docs/tutorials/restful.zh-CN.md | 149 +- site/docs/tutorials/sequelize.md | 88 +- site/docs/tutorials/sequelize.zh-CN.md | 99 +- site/docs/tutorials/socketio.md | 142 +- site/docs/tutorials/socketio.zh-CN.md | 262 +- site/docs/tutorials/typescript.md | 89 +- site/docs/tutorials/typescript.zh-CN.md | 114 +- site/global.less | 5 +- site/typings.d.ts | 4 +- test/agent.test.js | 20 +- test/app/extend/agent.test.js | 49 +- test/app/extend/application.test.js | 237 +- test/app/extend/context.jsonp.test.js | 49 +- test/app/extend/context.test.js | 444 ++- test/app/extend/helper.test.js | 58 +- test/app/extend/request.test.js | 524 ++- test/app/extend/response.test.js | 67 +- test/app/middleware/body_parser.test.js | 182 +- test/app/middleware/meta.test.js | 83 +- test/app/middleware/notfound.test.js | 92 +- test/app/middleware/override_method.test.js | 58 +- test/app/middleware/site_file.test.js | 135 +- test/asyncSupport.test.js | 21 +- test/bench/hello/app/controller/home.js | 6 +- test/bench/hello/app/router.js | 6 +- test/bench/hello/config/config.default.js | 4 +- test/bench/server.js | 14 +- test/fixtures/apps/agent-app-sync/agent.js | 10 +- test/fixtures/apps/agent-app-sync/app.js | 12 +- .../apps/agent-app-sync/app/router.js | 8 +- .../agent-app-sync/config/config.default.js | 4 +- test/fixtures/apps/agent-app/app.js | 22 +- test/fixtures/apps/agent-app/app/router.js | 34 +- .../apps/agent-app/config/config.default.js | 4 +- test/fixtures/apps/agent-app/config/plugin.js | 6 +- .../agent-app/plugins/mock-client/agent.js | 16 +- .../apps/agent-app/plugins/mock-client/app.js | 93 +- .../mock-client/config/config.default.js | 6 +- .../plugins/mock-client/mock_client.js | 32 +- test/fixtures/apps/agent-client-app/agent.js | 8 +- test/fixtures/apps/agent-client-app/app.js | 4 +- .../apps/agent-client-app/app/router.js | 38 +- .../agent-client-app/config/config.default.js | 4 +- test/fixtures/apps/agent-die/agent.js | 3 +- .../apps/agent-die/config/config.default.js | 4 +- test/fixtures/apps/agent-die/start.js | 12 +- .../config/config.default.js | 4 +- test/fixtures/apps/agent-restart/agent.js | 14 +- test/fixtures/apps/agent-restart/app.js | 12 +- test/fixtures/apps/agent-restart/client.js | 2 +- .../agent-restart/config/config.default.js | 4 +- test/fixtures/apps/agent-throw/agent.js | 12 +- test/fixtures/apps/agent-throw/app/router.js | 16 +- .../apps/agent-throw/config/config.default.js | 2 +- .../agent-throw/config/config.unittest.js | 4 +- .../aliyun-egg-app/app/controller/home.js | 12 +- .../apps/aliyun-egg-app/app/router.js | 6 +- .../aliyun-egg-app/config/config.default.js | 2 +- test/fixtures/apps/aliyun-egg-biz/index.js | 4 +- test/fixtures/apps/aliyun-egg/agent.js | 6 +- test/fixtures/apps/aliyun-egg/app.js | 6 +- .../apps/aliyun-egg/config/config.default.js | 4 +- .../fixtures/apps/aliyun-egg/config/plugin.js | 6 +- test/fixtures/apps/aliyun-egg/index.js | 8 +- test/fixtures/apps/aliyun-egg/lib/agent.js | 11 +- .../apps/aliyun-egg/lib/aliyun-egg.js | 14 +- .../aliyun-egg/lib/plugins/custom/agent.js | 10 +- .../apps/aliyun-egg/lib/plugins/custom/app.js | 10 +- .../app-config-cookies/app/controller/home.js | 6 +- .../apps/app-config-cookies/app/router.js | 4 +- .../config/config.default.js | 6 +- .../apps/app-die-ignore-code/app/router.js | 10 +- .../config/config.default.js | 4 +- test/fixtures/apps/app-die/app/router.js | 10 +- .../apps/app-die/config/config.default.js | 2 +- .../app/controller/home.js | 4 +- .../app-enableFastContextLogger/app/router.js | 4 +- .../config/config.default.js | 2 +- .../app/controller/home.js | 2 +- .../app/router.js | 4 +- .../config/config.default.js | 6 +- .../config/config.unittest.js | 4 +- .../apps/app-locals-getter/app/router.js | 10 +- .../config/config.default.js | 2 +- .../apps/app-router/app/controller/home.js | 2 +- test/fixtures/apps/app-router/app/router.js | 6 +- .../apps/app-router/config/config.default.js | 4 +- .../app.js | 33 +- .../config/config.default.js | 2 +- .../config/config.unittest.js | 2 +- .../app-runInAnonymousContextScope/app.js | 10 +- .../config/config.default.js | 2 +- .../config/config.unittest.js | 2 +- .../app-server-customized-client-error/app.js | 6 +- .../app/router.js | 6 +- .../config/config.default.js | 8 +- test/fixtures/apps/app-server-timeout/app.js | 18 +- .../apps/app-server-timeout/app/router.js | 12 +- .../config/config.default.js | 2 +- .../app-server-with-hostname/app/router.js | 8 +- .../config/config.default.js | 6 +- test/fixtures/apps/app-server/app.js | 6 +- test/fixtures/apps/app-server/app/router.js | 4 +- .../apps/app-server/config/config.default.js | 2 +- test/fixtures/apps/app-start-timeout/app.js | 6 +- .../config/config.default.js | 2 +- .../config/config.unittest.js | 4 +- test/fixtures/apps/app-throw/app/router.js | 42 +- .../apps/app-throw/config/config.default.js | 4 +- .../apps/app-throw/config/config.unittest.js | 4 +- .../apps/app-ts-esm/app/controller/foo.ts | 6 +- test/fixtures/apps/app-ts-esm/app/router.ts | 6 +- .../fixtures/apps/app-ts-esm/config/config.ts | 4 +- test/fixtures/apps/app-ts-esm/package.json | 2 +- test/fixtures/apps/app-ts-esm/tsconfig.json | 2 +- test/fixtures/apps/app-ts-type-check/error.ts | 17 +- .../apps/app-ts-type-check/framework.ts | 55 +- .../fixtures/apps/app-ts-type-check/normal.ts | 177 +- .../app-ts-type-check/tsconfig-error.json | 2 +- .../apps/app-ts-type-check/tsconfig.json | 8 +- test/fixtures/apps/app-ts/app.ts | 20 +- .../apps/app-ts/app/controller/foo.ts | 76 +- .../apps/app-ts/app/extend/context.ts | 4 +- .../fixtures/apps/app-ts/app/extend/helper.ts | 6 +- .../apps/app-ts/app/middleware/default_ctx.ts | 4 +- .../apps/app-ts/app/middleware/generic_ctx.ts | 4 +- .../apps/app-ts/app/middleware/test.ts | 4 +- test/fixtures/apps/app-ts/app/router.ts | 10 +- test/fixtures/apps/app-ts/app/service/foo.ts | 4 +- test/fixtures/apps/app-ts/config/config.ts | 10 +- test/fixtures/apps/app-ts/lib/export-class.ts | 16 +- test/fixtures/apps/app-ts/lib/logger.ts | 20 +- test/fixtures/apps/app-ts/package.json | 2 +- test/fixtures/apps/app-ts/tsconfig.json | 4 +- test/fixtures/apps/async-app/app.js | 6 +- .../apps/async-app/app/controller/api.js | 6 +- .../apps/async-app/app/middleware/async.js | 4 +- .../apps/async-app/app/middleware/router.js | 4 +- test/fixtures/apps/async-app/app/router.js | 6 +- .../apps/async-app/app/schedule/async.js | 4 +- .../apps/async-app/app/service/api.js | 8 +- .../apps/async-app/config/config.default.js | 6 +- .../base-context-class/app/controller/home.js | 18 +- .../apps/base-context-class/app/router.js | 10 +- .../base-context-class/app/service/home.js | 20 +- .../config/config.default.js | 4 +- .../config/config.unittest.js | 4 +- .../apps/body_parser_testapp/app/router.js | 14 +- .../config/config.default.js | 12 +- .../body_parser_testapp_disable/app/router.js | 12 +- .../config/config.default.js | 2 +- .../body_parser_testapp_ignore/app/router.js | 12 +- .../config/config.default.js | 4 +- .../body_parser_testapp_match/app/router.js | 12 +- .../config/config.default.js | 4 +- test/fixtures/apps/boot-app/agent.js | 24 +- test/fixtures/apps/boot-app/app.js | 22 +- .../config/config.default.js | 2 +- .../fixtures/apps/cluster-client-error/app.js | 6 +- .../config/config.default.js | 4 +- test/fixtures/apps/cluster_mod_app/agent.js | 12 +- test/fixtures/apps/cluster_mod_app/app.js | 25 +- .../cluster_mod_app/app/controller/home.js | 18 +- .../apps/cluster_mod_app/app/router.js | 16 +- .../cluster_mod_app/config/config.default.js | 2 +- .../apps/cluster_mod_app/lib/api_client.js | 8 +- .../apps/cluster_mod_app/lib/api_client_2.js | 8 +- .../cluster_mod_app/lib/registry_client.js | 11 +- .../apps/config-env/config/config.default.js | 2 +- .../fixtures/apps/config-env/config/plugin.js | 2 +- .../config/config.default.js | 2 +- .../context-config-app/app/controller/home.js | 8 +- .../context-config-app/app/extend/context.js | 6 +- .../apps/context-config-app/app/router.js | 4 +- .../apps/context-config-app/config/config.js | 6 +- .../context-config-app/config/config.local.js | 4 +- .../config/config.default.js | 4 +- .../config/config.default.js | 4 +- .../apps/csrf-disable/app/controller/api.js | 2 +- test/fixtures/apps/csrf-disable/app/router.js | 6 +- .../csrf-disable/config/config.default.js | 6 +- .../apps/csrf-enable/app/controller/api.js | 2 +- test/fixtures/apps/csrf-enable/app/router.js | 8 +- .../apps/csrf-enable/config/config.default.js | 4 +- .../csrf-enable/config/config.unittest.js | 4 +- .../apps/csrf-ignore/app/controller/api.js | 2 +- test/fixtures/apps/csrf-ignore/app/router.js | 8 +- .../apps/csrf-ignore/config/config.default.js | 4 +- .../csrf-ignore/config/config.unittest.js | 4 +- .../apps/ctx-background/app/controller/app.js | 12 +- .../ctx-background/app/controller/custom.js | 10 +- .../ctx-background/app/controller/error.js | 10 +- .../ctx-background/app/controller/home.js | 12 +- .../ctx-background/app/controller/sync.js | 7 +- .../apps/ctx-background/app/router.js | 15 +- .../ctx-background/config/config.default.js | 4 +- .../ctx-background/config/config.unittest.js | 4 +- .../app/controller/home.js | 8 +- .../app/extend/context.js | 4 +- .../custom-context-getlogger/app/router.js | 6 +- .../config/config.default.js | 4 +- .../apps/custom-env-app/app/router.js | 6 +- .../custom-env-app/config/config.default.js | 4 +- .../apps/custom-framework-demo/app.js | 8 +- .../app/controller/foo.js | 8 +- .../app/controller/hello.js | 8 +- .../app/controller/home.js | 2 +- .../app/controller/ip.js | 2 +- .../app/controller/logger.js | 22 +- .../app/controller/obj.js | 14 +- .../app/controller/obj2.js | 14 +- .../apps/custom-framework-demo/app/router.js | 30 +- .../config/config.default.js | 28 +- .../apps/custom-framework-demo/index.js | 6 +- test/fixtures/apps/custom-loader/app.js | 2 +- .../apps/custom-loader/app/adapter/docker.js | 5 +- .../apps/custom-loader/app/controller/user.js | 2 +- .../apps/custom-loader/app/repository/user.js | 5 +- .../fixtures/apps/custom-loader/app/router.js | 8 +- .../custom-loader/config/config.default.js | 12 +- .../fixtures/apps/custom-logger/app/router.js | 12 +- .../custom-logger/config/config.default.js | 10 +- test/fixtures/apps/demo/app.js | 15 +- test/fixtures/apps/demo/app/controller/foo.js | 8 +- .../apps/demo/app/controller/hello.js | 8 +- .../fixtures/apps/demo/app/controller/home.js | 2 +- test/fixtures/apps/demo/app/controller/ip.js | 2 +- .../apps/demo/app/controller/logger.js | 22 +- test/fixtures/apps/demo/app/controller/obj.js | 14 +- .../fixtures/apps/demo/app/controller/obj2.js | 14 +- test/fixtures/apps/demo/app/router.js | 30 +- .../apps/demo/config/config.default.js | 28 +- test/fixtures/apps/demo/index.js | 6 +- .../apps/development/app/public/foo.js | 2 +- test/fixtures/apps/development/app/router.js | 12 +- .../apps/development/config/config.default.js | 2 +- .../apps/dns_resolver/app/controller/home.js | 2 +- test/fixtures/apps/dns_resolver/app/router.js | 6 +- .../dns_resolver/config/config.default.js | 8 +- .../app/controller/home.js | 2 +- .../apps/dnscache_httpclient/app/router.js | 6 +- .../config/config.default.js | 4 +- .../config/config.unittest.js | 4 +- .../apps/docapp/app/middleware/koastatic.js | 6 +- .../apps/docapp/config/config.default.js | 8 +- .../config/config.default.js | 3 +- .../config/config.default.js | 6 +- .../config/config.unittest.js | 2 +- .../dump-ignore-key-path/config/plugin.js | 2 +- test/fixtures/apps/dumpconfig-circular/app.js | 6 +- .../config/config.default.js | 2 +- test/fixtures/apps/dumpconfig/app.js | 20 +- .../apps/dumpconfig/config/config.default.js | 2 +- .../fixtures/apps/dumpconfig/config/plugin.js | 2 +- .../app.js | 8 +- .../config/config.default.js | 2 +- test/fixtures/apps/dumptiming-timeout/app.js | 10 +- .../config/config.default.js | 2 +- .../apps/dumptiming-timeout/config/plugin.js | 2 +- .../apps/empty/config/config.default.js | 4 +- .../encrypt-cookies/app/controller/home.js | 16 +- .../apps/encrypt-cookies/app/router.js | 4 +- .../encrypt-cookies/config/config.default.js | 2 +- .../favicon-function/app/controller/home.js | 4 +- .../apps/favicon-function/app/router.js | 6 +- .../favicon-function/config/config.default.js | 8 +- .../apps/favicon/app/controller/home.js | 6 +- test/fixtures/apps/favicon/app/router.js | 6 +- .../apps/favicon/config/config.default.js | 6 +- test/fixtures/apps/fetch-tracer/app.js | 12 +- test/fixtures/apps/fetch-tracer/app/router.js | 14 +- .../fetch-tracer/config/config.default.js | 8 +- .../apps/fetch_factory/app/controller/home.js | 2 +- .../fixtures/apps/fetch_factory/app/router.js | 6 +- .../fetch_factory/config/config.default.js | 4 +- test/fixtures/apps/get-logger/app/router.js | 14 +- .../fixtures/apps/get-logger/config/config.js | 10 +- .../apps/helper/app/controller/home.js | 2 +- test/fixtures/apps/helper/app/router.js | 38 +- .../apps/helper/config/config.default.js | 12 +- .../config/config.default.js | 8 +- test/fixtures/apps/httpclient-allowH2/app.js | 6 +- .../apps/httpclient-next-overwrite/app.js | 10 +- .../config/config.default.js | 2 +- .../config/config.default.js | 2 +- .../config/plugin.js | 6 +- .../fixtures/apps/httpclient-overwrite/app.js | 10 +- .../config/config.default.js | 2 +- .../config/config.default.js | 2 +- .../apps/httpclient-retry/package.json | 2 +- test/fixtures/apps/httpclient-tracer/app.js | 26 +- .../apps/httpclient-tracer/config/plugin.js | 6 +- .../fixtures/apps/i18n/app/controller/home.js | 6 +- .../apps/i18n/app/controller/message.js | 20 +- test/fixtures/apps/i18n/app/router.js | 8 +- .../apps/i18n/config/config.default.js | 6 +- .../apps/i18n/config/locales/zh-CN.js | 4 +- test/fixtures/apps/i18n/config/plugin.js | 6 +- .../apps/keys-exists/config/config.default.js | 2 +- .../apps/koa-session/app/controller/clear.js | 3 +- .../apps/koa-session/app/controller/home.js | 1 - test/fixtures/apps/koa-session/app/router.js | 7 +- .../apps/koa-session/config/config.default.js | 2 +- .../config/config.default.js | 4 +- .../config/plugin.js | 15 +- .../config/config.default.js | 4 +- .../config/plugin.js | 15 +- .../config/config.default.js | 4 +- .../apps/loader-plugin-dep/config/plugin.js | 25 +- .../config/config.default.js | 4 +- .../loader-plugin-noexist/config/plugin.js | 4 +- test/fixtures/apps/loader-plugin/app.js | 6 +- .../fixtures/apps/loader-plugin/app/router.js | 6 +- .../apps/loader-plugin/app/service/Foo4.js | 6 +- .../apps/loader-plugin/app/service/foo.js | 6 +- .../apps/loader-plugin/app/service/foo2.js | 4 +- .../loader-plugin/app/service/foo3/foo3.js | 4 +- .../loader-plugin/app/service/fooDir/Foo5.js | 6 +- .../loader-plugin/config/config.default.js | 4 +- .../apps/loader-plugin/config/plugin.js | 18 +- .../apps/loader-plugin/plugins/e/package.json | 4 +- .../apps/loader-plugin/plugins/g/package.json | 4 +- test/fixtures/apps/locals/app.js | 8 +- test/fixtures/apps/locals/app/helper.js | 4 +- test/fixtures/apps/locals/app/router.js | 79 +- .../apps/locals/config/config.default.js | 2 +- .../apps/logger-level-debug/app/router.js | 10 +- .../config/config.default.js | 6 +- .../config/config.default.js | 2 +- .../apps/logger-reload/app/controller/home.js | 6 +- .../fixtures/apps/logger-reload/app/router.js | 4 +- .../logger-reload/config/config.default.js | 4 +- test/fixtures/apps/logger/agent.js | 8 +- test/fixtures/apps/logger/app.js | 10 +- .../apps/logger/config/config.default.js | 10 +- .../apps/logger/config/config.local.js | 4 +- .../apps/logger/config/config.unittest.js | 4 +- .../apps/logrotator-app/app/router.js | 6 +- .../logrotator-app/config/config.default.js | 8 +- .../config/config.default.js | 2 +- .../dispatch.js | 4 +- .../config/config.default.js | 4 +- .../apps/master-worker-started/dispatch.js | 6 +- .../apps/messenger-app-agent/agent.js | 14 +- test/fixtures/apps/messenger-app-agent/app.js | 14 +- .../config/config.default.js | 4 +- .../apps/messenger-broadcast/agent.js | 14 +- test/fixtures/apps/messenger-broadcast/app.js | 14 +- .../config/config.default.js | 4 +- test/fixtures/apps/messenger-random/agent.js | 8 +- test/fixtures/apps/messenger-random/app.js | 6 +- .../messenger-random/config/config.default.js | 4 +- test/fixtures/apps/messenger/agent.js | 32 +- test/fixtures/apps/messenger/app.js | 20 +- .../apps/messenger/config/config.default.js | 4 +- test/fixtures/apps/meta-logging-app/app.js | 8 +- .../meta-logging-app/app/controller/home.js | 6 +- .../apps/meta-logging-app/app/router.js | 6 +- .../meta-logging-app/config/config.default.js | 2 +- .../app/controller/home.js | 6 +- .../app/router.js | 6 +- .../config/config.default.js | 8 +- .../apps/middlewares/app/controller/error.js | 4 +- .../apps/middlewares/app/controller/home.js | 6 +- test/fixtures/apps/middlewares/app/router.js | 8 +- .../apps/middlewares/config/config.default.js | 14 +- .../mock-dev-app/config/config.default.js | 2 +- .../config/config.js | 8 +- .../config/config.unittest.js | 4 +- .../config/map.json | 4 +- .../apps/mock-production-app/config/config.js | 8 +- .../config/config.unittest.js | 4 +- .../apps/mock-production-app/config/map.json | 4 +- .../apps/multipart/app/controller/home.js | 6 +- .../apps/multipart/app/controller/upload.js | 12 +- test/fixtures/apps/multipart/app/router.js | 6 +- .../apps/multipart/app/view/home.html | 3 +- .../apps/multipart/config/config.default.js | 6 +- .../fixtures/apps/multiple-view-engine/app.js | 8 +- .../app/controller/view.js | 19 +- .../apps/multiple-view-engine/app/router.js | 14 +- .../config/config.default.js | 25 +- .../config/config.unittest.js | 4 +- .../fixtures/apps/multiple-view-engine/ejs.js | 6 +- .../apps/multiple-view-engine/nunjucks.js | 4 +- .../nobuffer-logger/config/config.default.js | 4 +- .../apps/notfound-custom-404/app/router.js | 6 +- .../config/config.default.js | 4 +- .../apps/notfound/config/config.default.js | 4 +- test/fixtures/apps/notready/a/app.js | 6 +- .../apps/notready/config/config.default.js | 4 +- test/fixtures/apps/notready/config/plugin.js | 8 +- .../apps/onerror/app/controller/home.js | 20 +- .../apps/onerror/app/controller/user.js | 10 +- test/fixtures/apps/onerror/app/router.js | 10 +- .../apps/onerror/config/config.default.js | 6 +- .../apps/onerror/config/config.unittest.js | 4 +- .../apps/override_method/app/router.js | 14 +- .../override_method/config/config.default.js | 2 +- .../apps/querystring-extended/app/router.js | 4 +- .../config/config.default.js | 6 +- .../apps/reload-worker/app/controller/home.js | 4 +- .../reload-worker/app/controller/home1.js | 4 +- .../fixtures/apps/reload-worker/app/router.js | 6 +- .../reload-worker/config/config.default.js | 4 +- test/fixtures/apps/response/app/router.js | 28 +- .../apps/response/config/config.default.js | 2 +- .../apps/router-app/app/controller/locals.js | 6 +- .../apps/router-app/app/controller/members.js | 10 +- .../apps/router-app/app/controller/posts.js | 18 +- test/fixtures/apps/router-app/app/router.js | 8 +- .../router-app/app/view/locals/router.html | 2 +- .../apps/router-app/config/config.default.js | 4 +- test/fixtures/apps/router-app/package.json | 2 +- .../apps/schedule/app/schedule/hello.js | 12 +- .../apps/schedule/app/schedule/sub/cron.js | 8 +- .../apps/schedule/config/config.default.js | 4 +- .../apps/secure-app/app/controller/index.js | 24 +- test/fixtures/apps/secure-app/app/router.js | 6 +- .../apps/secure-app/config/config.default.js | 2 +- .../apps/secure-app/config/config.unittest.js | 4 +- .../apps/service-app/app/controller/user.js | 2 +- test/fixtures/apps/service-app/app/router.js | 4 +- .../apps/service-app/app/service/user.js | 6 +- .../apps/service-app/config/config.default.js | 4 +- .../services_loader_verify/app/service/foo.js | 8 +- .../config/config.default.js | 4 +- test/fixtures/apps/singleton-demo/agent.js | 12 +- test/fixtures/apps/singleton-demo/app.js | 12 +- .../singleton-demo/config/config.default.js | 20 +- test/fixtures/apps/singleton-demo/create.js | 2 +- .../app/router.js | 6 +- .../config/config.default.js | 4 +- .../apps/static-server/app/public/foo.js | 2 +- .../static-server/config/config.default.js | 2 +- .../subdir-services/app/controller/home.js | 12 +- .../apps/subdir-services/app/router.js | 4 +- .../certify-personal/mobile-hi/do_certify.js | 4 +- .../subdir-services/app/service/cif/user.js | 4 +- .../subdir-services/app/service/foo/bar.js | 6 +- .../app/service/foo/subdir/bar.js | 6 +- .../app/service/foo/subdir1/subdir11/bar.js | 6 +- .../app/service/foo/subdir2/sub2.js | 8 +- .../apps/subdir-services/app/service/ok.js | 6 +- .../apps/subdir-services/app/service/user.js | 6 +- .../subdir-services/config/config.default.js | 4 +- test/fixtures/apps/tracer-demo/agent.js | 6 +- test/fixtures/apps/tracer-demo/app.js | 6 +- .../apps/tracer-demo/app/controller/foo.js | 12 +- .../apps/tracer-demo/app/controller/home.js | 4 +- test/fixtures/apps/tracer-demo/app/router.js | 8 +- .../apps/tracer-demo/config/config.default.js | 4 +- test/fixtures/apps/tracer-demo/tracer.js | 32 +- test/fixtures/apps/view-render/app/a.js | 2 +- .../apps/view-render/app/controller/async.js | 42 +- .../view-render/app/controller/context.js | 6 +- .../apps/view-render/app/controller/csrf.js | 4 +- .../apps/view-render/app/controller/empty.js | 2 +- .../apps/view-render/app/controller/home.js | 2 +- .../apps/view-render/app/controller/inject.js | 8 +- .../apps/view-render/app/controller/locals.js | 10 +- .../apps/view-render/app/controller/nonce.js | 4 +- .../apps/view-render/app/controller/shtml.js | 2 +- .../apps/view-render/app/controller/sjs.js | 4 +- .../apps/view-render/app/controller/string.js | 6 +- .../apps/view-render/app/controller/xss.js | 6 +- .../apps/view-render/app/extend/helper.js | 10 +- test/fixtures/apps/view-render/app/router.js | 26 +- .../fixtures/apps/view-render/app/view/a.html | 2 +- .../apps/view-render/app/view/index.html | 5 +- .../apps/view-render/app/view/inject.html | 6 +- .../apps/view-render/app/view/locals.html | 9 +- .../apps/view-render/app/view/nonce.html | 2 +- .../apps/view-render/app/view/xss.html | 5 +- .../apps/view-render/config/config.default.js | 4 +- .../apps/view-render/config/plugin.js | 4 +- .../apps/watcher-development-app/agent.js | 18 +- .../watcher-development-app/app/router.js | 32 +- .../config/config.unittest.js | 8 +- .../apps/watcher-development-app/package.json | 2 +- .../config/config.unittest.js | 6 +- .../apps/watcher-type-default/package.json | 2 +- test/fixtures/apps/worker-die/app.js | 2 +- .../apps/worker-die/config/config.default.js | 4 +- test/fixtures/custom-egg/index.js | 6 +- test/index.test.js | 32 +- test/lib/agent.test.js | 62 +- test/lib/application.test.js | 229 +- test/lib/cluster/app_worker.test.js | 117 +- test/lib/cluster/cluster-client-error.test.js | 26 +- test/lib/cluster/cluster-client.test.js | 104 +- test/lib/cluster/master.test.js | 240 +- test/lib/core/config/config.cookies.test.js | 23 +- test/lib/core/config/config.test.js | 16 +- test/lib/core/context_httpclient.test.js | 16 +- .../core/context_httpclient_timeout.test.js | 10 +- .../context_performance_starttime.test.js | 19 +- test/lib/core/cookies.test.js | 281 +- test/lib/core/custom_loader.test.js | 29 +- test/lib/core/dns_resolver.test.js | 146 +- test/lib/core/dnscache_httpclient.test.js | 182 +- test/lib/core/fetch_factory.test.js | 23 +- test/lib/core/fetch_tracer.test.js | 66 +- test/lib/core/httpclient.test.js | 625 ++-- test/lib/core/httpclient_tracer_demo.test.js | 54 +- test/lib/core/loader/config_loader.test.js | 60 +- test/lib/core/loader/load_app.test.js | 22 +- test/lib/core/loader/load_boot.test.js | 52 +- test/lib/core/loader/load_plugin.test.js | 242 +- test/lib/core/loader/load_router.test.js | 22 +- test/lib/core/loader/load_service.test.js | 83 +- test/lib/core/logger.test.js | 287 +- test/lib/core/messenger/ipc.test.js | 120 +- test/lib/core/messenger/local.test.js | 190 +- test/lib/core/router.test.js | 166 +- test/lib/core/singleton.test.js | 216 +- test/lib/core/utils.test.js | 331 +- test/lib/core/view.test.js | 149 +- test/lib/egg.test.js | 433 +-- test/lib/plugins/depd.test.js | 16 +- test/lib/plugins/development.test.js | 50 +- test/lib/plugins/i18n.test.js | 69 +- test/lib/plugins/logrotator.test.js | 24 +- test/lib/plugins/multipart.test.js | 68 +- test/lib/plugins/onerror.test.js | 25 +- test/lib/plugins/schedule.test.js | 33 +- test/lib/plugins/security.test.js | 95 +- test/lib/plugins/session.test.js | 78 +- test/lib/plugins/static.test.js | 17 +- test/lib/plugins/watcher.test.js | 75 +- test/lib/start.test.js | 76 +- test/ts/index.test.js | 123 +- test/utils.js | 88 +- vite.config.ts | 275 ++ 667 files changed, 11094 insertions(+), 10706 deletions(-) create mode 100755 .vite-hooks/pre-commit create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 AGENTS.md delete mode 100644 eslint.config.mjs create mode 100644 vite.config.ts diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 5f59807ac1..5578d1a1aa 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -2,6 +2,7 @@ open_collective: eggjs # Replace with a single Open Collective username + # github: [ fengmk2, popomore, atian25, dead_horse ] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] # patreon: # Replace with a single Patreon username # ko_fi: # Replace with a single Ko-fi username diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 11bd06379e..4a715b6fec 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -42,7 +42,7 @@ body: description: | What's your Eggjs version? placeholder: | - See it directly in your "package.json" file (e.g: 3.1.0) + See it directly in your "package.json" file (e.g: 3.1.0) validations: required: true - type: input diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 954f1057f3..8ec9a4937a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,10 +13,10 @@ name: "CodeQL" on: push: - branches: [ 3.x ] + branches: [3.x] pull_request: # The branches below must be a subset of the branches above - branches: [ 3.x ] + branches: [3.x] jobs: analyze: @@ -30,39 +30,39 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'javascript' ] + language: ["javascript"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index fd81f760b3..3cdeab617b 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -2,7 +2,7 @@ name: Github Pages on: push: - branches: [ 3.x ] + branches: [3.x] jobs: Runner: @@ -10,25 +10,25 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-latest ] - node-version: [ 18 ] + os: [ubuntu-latest] + node-version: [18] steps: - - name: Checkout Git Source - uses: actions/checkout@master + - name: Checkout Git Source + uses: actions/checkout@master - - name: Setup Node.js - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} - - name: Install Dependencies - run: npm i -g npminstall && npminstall + - name: Install Dependencies + run: npm i -g npminstall && npminstall - - name: Build Documents - run: npm run site:build + - name: Build Documents + run: npm run site:build - - name: Deploy Documents - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./site/dist + - name: Deploy Documents + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site/dist diff --git a/.github/workflows/nodejs-3.x.yml b/.github/workflows/nodejs-3.x.yml index 18e684106e..13cab54956 100644 --- a/.github/workflows/nodejs-3.x.yml +++ b/.github/workflows/nodejs-3.x.yml @@ -2,19 +2,19 @@ name: CI for 3.x on: push: - branches: [ 3.x ] + branches: [3.x] pull_request: - branches: [ 3.x ] + branches: [3.x] merge_group: - branches: [ 3.x ] + branches: [3.x] jobs: Job: name: Node.js uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: - os: 'ubuntu-latest, macos-latest, windows-latest' - version: '14, 16, 18, 20, 22, 24' - install: 'npm i -g npminstall && npminstall' + os: "ubuntu-latest, macos-latest, windows-latest" + version: "14, 16, 18, 20, 22, 24" + install: "npm i -g npminstall && npminstall" secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index efb9f64be0..359b3e651a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,7 @@ name: Release 3.x on: push: - branches: [ 3.x ] + branches: [3.x] permissions: contents: write diff --git a/.vite-hooks/pre-commit b/.vite-hooks/pre-commit new file mode 100755 index 0000000000..85fb65b4fc --- /dev/null +++ b/.vite-hooks/pre-commit @@ -0,0 +1 @@ +vp staged diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..99e2f7ddf7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["oxc.oxc-vscode"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..7ab77f7a7c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "editor.defaultFormatter": "oxc.oxc-vscode", + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + "editor.codeActionsOnSave": { + "source.fixAll.oxc": "explicit" + }, + "oxc.typeAware": true +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..85734764bb --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,76 @@ + + +# Using Vite+, the Unified Toolchain for the Web + +This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`. + +## Vite+ Workflow + +`vp` is a global binary that handles the full development lifecycle. Run `vp help` to print a list of commands and `vp --help` for information about a specific command. + +### Start + +- create - Create a new project from a template +- migrate - Migrate an existing project to Vite+ +- config - Configure hooks and agent integration +- staged - Run linters on staged files +- install (`i`) - Install dependencies +- env - Manage Node.js versions + +### Develop + +- dev - Run the development server +- check - Run format, lint, and TypeScript type checks +- lint - Lint code +- fmt - Format code +- test - Run tests + +### Execute + +- run - Run monorepo tasks +- exec - Execute a command from local `node_modules/.bin` +- dlx - Execute a package binary without installing it as a dependency +- cache - Manage the task cache + +### Build + +- build - Build for production +- pack - Build libraries +- preview - Preview production build + +### Manage Dependencies + +Vite+ automatically detects and wraps the underlying package manager such as pnpm, npm, or Yarn through the `packageManager` field in `package.json` or package manager-specific lockfiles. + +- add - Add packages to dependencies +- remove (`rm`, `un`, `uninstall`) - Remove packages from dependencies +- update (`up`) - Update packages to latest versions +- dedupe - Deduplicate dependencies +- outdated - Check for outdated packages +- list (`ls`) - List installed packages +- why (`explain`) - Show why a package is installed +- info (`view`, `show`) - View package information from the registry +- link (`ln`) / unlink - Manage local package links +- pm - Forward a command to the package manager + +### Maintain + +- upgrade - Update `vp` itself to the latest version + +These commands map to their corresponding tools. For example, `vp dev --port 3000` runs Vite's dev server and works the same as Vite. `vp test` runs JavaScript tests through the bundled Vitest. The version of all tools can be checked using `vp --version`. This is useful when researching documentation, features, and bugs. + +## Common Pitfalls + +- **Using the package manager directly:** Do not use pnpm, npm, or Yarn directly. Vite+ can handle all package manager operations. +- **Always use Vite commands to run tools:** Don't attempt to run `vp vitest` or `vp oxlint`. They do not exist. Use `vp test` and `vp lint` instead. +- **Running scripts:** Vite+ commands take precedence over `package.json` scripts. If there is a `test` script defined in `scripts` that conflicts with the built-in `vp test` command, run it using `vp run test`. +- **Do not install Vitest, Oxlint, Oxfmt, or tsdown directly:** Vite+ wraps these tools. They must not be installed directly. You cannot upgrade these tools by installing their latest versions. Always use Vite+ commands. +- **Use Vite+ wrappers for one-off binaries:** Use `vp dlx` instead of package-manager-specific `dlx`/`npx` commands. +- **Import JavaScript modules from `vite-plus`:** Instead of importing from `vite` or `vitest`, all modules should be imported from the project's `vite-plus` dependency. For example, `import { defineConfig } from 'vite-plus';` or `import { expect, test, vi } from 'vite-plus/test';`. You must not install `vitest` to import test utilities. +- **Type-Aware Linting:** There is no need to install `oxlint-tsgolint`, `vp lint --type-aware` works out of the box. + +## Review Checklist for Agents + +- [ ] Run `vp install` after pulling remote changes and before getting started. +- [ ] Run `vp check` and `vp test` to validate changes. + diff --git a/CHANGELOG.md b/CHANGELOG.md index f61dd2d7cb..1e99e9531d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,253 +2,220 @@ ## 3.34.0 (2026-01-18) -* feat(core): support `config.httpclient.interceptors` for `fetch`/`safeFetch` tracer injection (#5771 ([fdfe958](https://github.com/eggjs/egg/commit/fdfe958)), closes [#5771](https://github.com/eggjs/egg/issues/5771) +- feat(core): support `config.httpclient.interceptors` for `fetch`/`safeFetch` tracer injection (#5771 ([fdfe958](https://github.com/eggjs/egg/commit/fdfe958)), closes [#5771](https://github.com/eggjs/egg/issues/5771) ## 3.33.1 (2026-01-16) -* fix: egg-mock for httpclient_next proxy (#5768) ([04cfa1b](https://github.com/eggjs/egg/commit/04cfa1b)), closes [#5768](https://github.com/eggjs/egg/issues/5768) +- fix: egg-mock for httpclient_next proxy (#5768) ([04cfa1b](https://github.com/eggjs/egg/commit/04cfa1b)), closes [#5768](https://github.com/eggjs/egg/issues/5768) ## 3.33.0 (2026-01-12) -* feat: httpclient_next proxy (#5763) ([a1169f3](https://github.com/eggjs/egg/commit/a1169f3)), closes [#5763](https://github.com/eggjs/egg/issues/5763) -* chore: rename to release.yml ([13d9a19](https://github.com/eggjs/egg/commit/13d9a19)) +- feat: httpclient_next proxy (#5763) ([a1169f3](https://github.com/eggjs/egg/commit/a1169f3)), closes [#5763](https://github.com/eggjs/egg/issues/5763) +- chore: rename to release.yml ([13d9a19](https://github.com/eggjs/egg/commit/13d9a19)) ## 3.32.0 (2025-12-24) -* feat: enable custom lookup for httpclient and fetch (#5749) ([4fa4d4b](https://github.com/eggjs/egg/commit/4fa4d4b)), closes [#5749](https://github.com/eggjs/egg/issues/5749) -* chore: fix auto release on 3.x ([e4d49a7](https://github.com/eggjs/egg/commit/e4d49a7)) -* chore: remove unuse actions ([5b4e3be](https://github.com/eggjs/egg/commit/5b4e3be)) +- feat: enable custom lookup for httpclient and fetch (#5749) ([4fa4d4b](https://github.com/eggjs/egg/commit/4fa4d4b)), closes [#5749](https://github.com/eggjs/egg/issues/5749) +- chore: fix auto release on 3.x ([e4d49a7](https://github.com/eggjs/egg/commit/e4d49a7)) +- chore: remove unuse actions ([5b4e3be](https://github.com/eggjs/egg/commit/5b4e3be)) ## [3.31.0](https://github.com/eggjs/egg/compare/v3.30.1...v3.31.0) (2025-07-04) - ### Features -* add urllib4 fetch ([#5424](https://github.com/eggjs/egg/issues/5424)) ([63d14da](https://github.com/eggjs/egg/commit/63d14da00170a73c55a7a12ab57dea93b8b2daa1)) +- add urllib4 fetch ([#5424](https://github.com/eggjs/egg/issues/5424)) ([63d14da](https://github.com/eggjs/egg/commit/63d14da00170a73c55a7a12ab57dea93b8b2daa1)) ## [3.30.1](https://github.com/eggjs/egg/compare/v3.30.0...v3.30.1) (2025-01-19) - ### Bug Fixes -* redefine urllib export types ([#5386](https://github.com/eggjs/egg/issues/5386)) ([02d9fdb](https://github.com/eggjs/egg/commit/02d9fdb7c127f9e8150bdb8f23977a2effeaf6ae)) +- redefine urllib export types ([#5386](https://github.com/eggjs/egg/issues/5386)) ([02d9fdb](https://github.com/eggjs/egg/commit/02d9fdb7c127f9e8150bdb8f23977a2effeaf6ae)) ## [3.30.0](https://github.com/eggjs/egg/compare/v3.29.0...v3.30.0) (2025-01-09) - ### Features -* dump ignore support key path ([#5380](https://github.com/eggjs/egg/issues/5380)) ([74346c2](https://github.com/eggjs/egg/commit/74346c2d056cab63c3c3a905c1e8afbf857451b4)) +- dump ignore support key path ([#5380](https://github.com/eggjs/egg/issues/5380)) ([74346c2](https://github.com/eggjs/egg/commit/74346c2d056cab63c3c3a905c1e8afbf857451b4)) ## [3.24.1](https://github.com/eggjs/egg/compare/v3.24.0...v3.24.1) (2024-06-07) - ### Bug Fixes -* serverTimeout default to 0 (no timeout) ([#5325](https://github.com/eggjs/egg/issues/5325)) ([44ab507](https://github.com/eggjs/egg/commit/44ab507b6299c849a2fe31bee54f3a1909aa9d53)) +- serverTimeout default to 0 (no timeout) ([#5325](https://github.com/eggjs/egg/issues/5325)) ([44ab507](https://github.com/eggjs/egg/commit/44ab507b6299c849a2fe31bee54f3a1909aa9d53)) ## [3.24.0](https://github.com/eggjs/egg/compare/v3.23.0...v3.24.0) (2024-06-07) - ### Features -* add bodyParser.onProtoPoisoning type define ([#5324](https://github.com/eggjs/egg/issues/5324)) ([b3582e0](https://github.com/eggjs/egg/commit/b3582e02d0f5d85edbc03f3f20c4cdcc65619dc1)) +- add bodyParser.onProtoPoisoning type define ([#5324](https://github.com/eggjs/egg/issues/5324)) ([b3582e0](https://github.com/eggjs/egg/commit/b3582e02d0f5d85edbc03f3f20c4cdcc65619dc1)) ## [3.23.0](https://github.com/eggjs/egg/compare/v3.22.0...v3.23.0) (2024-05-08) - ### Features -* use utility@2 ([#5312](https://github.com/eggjs/egg/issues/5312)) ([9bf5f22](https://github.com/eggjs/egg/commit/9bf5f22bfae44a1f44651efba7b3e167f9040714)) +- use utility@2 ([#5312](https://github.com/eggjs/egg/issues/5312)) ([9bf5f22](https://github.com/eggjs/egg/commit/9bf5f22bfae44a1f44651efba7b3e167f9040714)) ## [3.22.0](https://github.com/eggjs/egg/compare/v3.21.0...v3.22.0) (2024-04-12) - ### Features -* app.httpClient alias to app.httpclient ([#5304](https://github.com/eggjs/egg/issues/5304)) ([a6ebe0f](https://github.com/eggjs/egg/commit/a6ebe0f49a9e1a8506c26a0bb4e89a32528aa727)) +- app.httpClient alias to app.httpclient ([#5304](https://github.com/eggjs/egg/issues/5304)) ([a6ebe0f](https://github.com/eggjs/egg/commit/a6ebe0f49a9e1a8506c26a0bb4e89a32528aa727)) ## [3.21.0](https://github.com/eggjs/egg/compare/v3.20.0...v3.21.0) (2024-03-31) - ### Features -* tiny improvements for "convertValue" ([#5302](https://github.com/eggjs/egg/issues/5302)) ([794d7f3](https://github.com/eggjs/egg/commit/794d7f3e89c2a283e38d2082b407b79e480f0b50)) +- tiny improvements for "convertValue" ([#5302](https://github.com/eggjs/egg/issues/5302)) ([794d7f3](https://github.com/eggjs/egg/commit/794d7f3e89c2a283e38d2082b407b79e480f0b50)) ## [3.20.0](https://github.com/eggjs/egg/compare/v3.19.0...v3.20.0) (2024-02-22) - ### Features -* urllib-next alias to npm:urllib ([#5299](https://github.com/eggjs/egg/issues/5299)) ([61cd51d](https://github.com/eggjs/egg/commit/61cd51d02a86cb6ca8d510fb3ea3a1ed73f7beec)) +- urllib-next alias to npm:urllib ([#5299](https://github.com/eggjs/egg/issues/5299)) ([61cd51d](https://github.com/eggjs/egg/commit/61cd51d02a86cb6ca8d510fb3ea3a1ed73f7beec)) ## [3.19.0](https://github.com/eggjs/egg/compare/v3.18.0...v3.19.0) (2024-02-08) - ### Features -* 优化中文文档表达 ([#5290](https://github.com/eggjs/egg/issues/5290)) ([d73046b](https://github.com/eggjs/egg/commit/d73046bb9165c74473b6f28842de23c880e78a87)) +- 优化中文文档表达 ([#5290](https://github.com/eggjs/egg/issues/5290)) ([d73046b](https://github.com/eggjs/egg/commit/d73046bb9165c74473b6f28842de23c880e78a87)) ## [3.18.0](https://github.com/eggjs/egg/compare/v3.17.7...v3.18.0) (2024-01-21) - ### Features -* auto set custom logger with onelogger ([#5287](https://github.com/eggjs/egg/issues/5287)) ([1fd79a2](https://github.com/eggjs/egg/commit/1fd79a2715b4eded47ae77d955de5fa50efa573b)) +- auto set custom logger with onelogger ([#5287](https://github.com/eggjs/egg/issues/5287)) ([1fd79a2](https://github.com/eggjs/egg/commit/1fd79a2715b4eded47ae77d955de5fa50efa573b)) ## [3.17.7](https://github.com/eggjs/egg/compare/v3.17.6...v3.17.7) (2024-01-11) - ### Bug Fixes -* omit koa application ctxStorage and currentContext define ([#5285](https://github.com/eggjs/egg/issues/5285)) ([4c24dac](https://github.com/eggjs/egg/commit/4c24dac1e9ec86051d806dd6940c1d5095723b4d)) +- omit koa application ctxStorage and currentContext define ([#5285](https://github.com/eggjs/egg/issues/5285)) ([4c24dac](https://github.com/eggjs/egg/commit/4c24dac1e9ec86051d806dd6940c1d5095723b4d)) ## [3.17.6](https://github.com/eggjs/egg/compare/v3.17.5...v3.17.6) (2024-01-10) - ### Bug Fixes -* typo on index.d.ts ([#5284](https://github.com/eggjs/egg/issues/5284)) ([17ee60b](https://github.com/eggjs/egg/commit/17ee60b35a48c22eb90f392b688b4347c44b490d)) +- typo on index.d.ts ([#5284](https://github.com/eggjs/egg/issues/5284)) ([17ee60b](https://github.com/eggjs/egg/commit/17ee60b35a48c22eb90f392b688b4347c44b490d)) ## [3.17.5](https://github.com/eggjs/egg/compare/v3.17.4...v3.17.5) (2023-10-12) - ### Bug Fixes -* set body parser error to status 400 by default ([#5262](https://github.com/eggjs/egg/issues/5262)) ([5ac26a3](https://github.com/eggjs/egg/commit/5ac26a39b4256b6a3fcd55da947a47a82811c7c1)) +- set body parser error to status 400 by default ([#5262](https://github.com/eggjs/egg/issues/5262)) ([5ac26a3](https://github.com/eggjs/egg/commit/5ac26a39b4256b6a3fcd55da947a47a82811c7c1)) ## [3.17.4](https://github.com/eggjs/egg/compare/v3.17.3...v3.17.4) (2023-08-01) - ### Bug Fixes -* use app.logger instead of ctx.logger ([#5246](https://github.com/eggjs/egg/issues/5246)) ([b700fb9](https://github.com/eggjs/egg/commit/b700fb962a866c6e699f5c88b342960cc5ee0b78)), closes [/github.com/eggjs/egg/issues/5213#issuecomment-1657771583](https://github.com/eggjs//github.com/eggjs/egg/issues/5213/issues/issuecomment-1657771583) +- use app.logger instead of ctx.logger ([#5246](https://github.com/eggjs/egg/issues/5246)) ([b700fb9](https://github.com/eggjs/egg/commit/b700fb962a866c6e699f5c88b342960cc5ee0b78)), closes [/github.com/eggjs/egg/issues/5213#issuecomment-1657771583](https://github.com/eggjs//github.com/eggjs/egg/issues/5213/issues/issuecomment-1657771583) ## [3.17.3](https://github.com/eggjs/egg/compare/v3.17.2...v3.17.3) (2023-06-29) - ### Bug Fixes -* add missing args definition on runSchedule ([#5232](https://github.com/eggjs/egg/issues/5232)) ([f90763b](https://github.com/eggjs/egg/commit/f90763b164897bf4992b6ec58c4eae20775c0006)) +- add missing args definition on runSchedule ([#5232](https://github.com/eggjs/egg/issues/5232)) ([f90763b](https://github.com/eggjs/egg/commit/f90763b164897bf4992b6ec58c4eae20775c0006)) ## [3.17.2](https://github.com/eggjs/egg/compare/v3.17.1...v3.17.2) (2023-06-25) - ### Bug Fixes -* don't require inspector module on production env ([#5228](https://github.com/eggjs/egg/issues/5228)) ([398fe15](https://github.com/eggjs/egg/commit/398fe15eb28c3bbe8d79a0c2b129d55922f45a9a)) +- don't require inspector module on production env ([#5228](https://github.com/eggjs/egg/issues/5228)) ([398fe15](https://github.com/eggjs/egg/commit/398fe15eb28c3bbe8d79a0c2b129d55922f45a9a)) ## [3.17.1](https://github.com/eggjs/egg/compare/v3.17.0...v3.17.1) (2023-06-22) - ### Bug Fixes -* compatible with content-type extra semicolon ([#5217](https://github.com/eggjs/egg/issues/5217)) ([cfdca36](https://github.com/eggjs/egg/commit/cfdca36b4ee84397ed2cb1987982d502a3c8af0a)) +- compatible with content-type extra semicolon ([#5217](https://github.com/eggjs/egg/issues/5217)) ([cfdca36](https://github.com/eggjs/egg/commit/cfdca36b4ee84397ed2cb1987982d502a3c8af0a)) ## [3.17.0](https://github.com/eggjs/egg/compare/v3.16.1...v3.17.0) (2023-06-19) - ### Features -* add getSingletonInstance alias to singleton.get(id) ([#5216](https://github.com/eggjs/egg/issues/5216)) ([9868768](https://github.com/eggjs/egg/commit/98687685bb095d37166d3a66890f0164428a8e53)) +- add getSingletonInstance alias to singleton.get(id) ([#5216](https://github.com/eggjs/egg/issues/5216)) ([9868768](https://github.com/eggjs/egg/commit/98687685bb095d37166d3a66890f0164428a8e53)) ## [3.16.1](https://github.com/eggjs/egg/compare/v3.16.0...v3.16.1) (2023-06-15) - ### Bug Fixes -* ipc not work with worker_threads mode ([#5210](https://github.com/eggjs/egg/issues/5210)) ([03c8cf7](https://github.com/eggjs/egg/commit/03c8cf743d1fb56a55dbc633f088b08410423c5a)) +- ipc not work with worker_threads mode ([#5210](https://github.com/eggjs/egg/issues/5210)) ([03c8cf7](https://github.com/eggjs/egg/commit/03c8cf743d1fb56a55dbc633f088b08410423c5a)) ## [3.16.0](https://github.com/eggjs/egg/compare/v3.15.0...v3.16.0) (2023-05-10) - ### Features -* use egg-security@3.0.0 ([#5182](https://github.com/eggjs/egg/issues/5182)) ([a13b35e](https://github.com/eggjs/egg/commit/a13b35e05ca660fee3663db9381cdf44d63e44a0)) +- use egg-security@3.0.0 ([#5182](https://github.com/eggjs/egg/issues/5182)) ([a13b35e](https://github.com/eggjs/egg/commit/a13b35e05ca660fee3663db9381cdf44d63e44a0)) ## [3.15.0](https://github.com/eggjs/egg/compare/v3.14.2...v3.15.0) (2023-01-28) - ### Features -* runInAnonymousContextScope support req ([#5134](https://github.com/eggjs/egg/issues/5134)) ([615d660](https://github.com/eggjs/egg/commit/615d6608ab2fc66af848fb82ce41ed359f41bfb0)) +- runInAnonymousContextScope support req ([#5134](https://github.com/eggjs/egg/issues/5134)) ([615d660](https://github.com/eggjs/egg/commit/615d6608ab2fc66af848fb82ce41ed359f41bfb0)) ## [3.14.2](https://github.com/eggjs/egg/compare/v3.14.1...v3.14.2) (2023-01-20) - ### Bug Fixes -* **types:** app.router.url params should be optional ([#5132](https://github.com/eggjs/egg/issues/5132)) ([dda6bb3](https://github.com/eggjs/egg/commit/dda6bb3674af4acbdd7d5eb2f2ca373c714c7d2d)) +- **types:** app.router.url params should be optional ([#5132](https://github.com/eggjs/egg/issues/5132)) ([dda6bb3](https://github.com/eggjs/egg/commit/dda6bb3674af4acbdd7d5eb2f2ca373c714c7d2d)) ## [3.14.1](https://github.com/eggjs/egg/compare/v3.14.0...v3.14.1) (2023-01-17) - ### Bug Fixes -* export urllib types directly ([#5128](https://github.com/eggjs/egg/issues/5128)) ([483bf1d](https://github.com/eggjs/egg/commit/483bf1d12bee5157f9a95e0a5b7403fc7562900e)) +- export urllib types directly ([#5128](https://github.com/eggjs/egg/issues/5128)) ([483bf1d](https://github.com/eggjs/egg/commit/483bf1d12bee5157f9a95e0a5b7403fc7562900e)) ## [3.14.0](https://github.com/eggjs/egg/compare/v3.13.0...v3.14.0) (2023-01-17) - ### Features -* export urllib types ([#5127](https://github.com/eggjs/egg/issues/5127)) ([1f7b082](https://github.com/eggjs/egg/commit/1f7b08298ff4c6f118b93d3b3bf8e1fb3ac37db1)) +- export urllib types ([#5127](https://github.com/eggjs/egg/issues/5127)) ([1f7b082](https://github.com/eggjs/egg/commit/1f7b08298ff4c6f118b93d3b3bf8e1fb3ac37db1)) ## [3.13.0](https://github.com/eggjs/egg/compare/v3.12.0...v3.13.0) (2023-01-13) - ### Features -* log app start timeline on coreLogger ([#5122](https://github.com/eggjs/egg/issues/5122)) ([6c4e8bc](https://github.com/eggjs/egg/commit/6c4e8bca1b829ecd47e98cc9b0544c7aa874e755)) +- log app start timeline on coreLogger ([#5122](https://github.com/eggjs/egg/issues/5122)) ([6c4e8bc](https://github.com/eggjs/egg/commit/6c4e8bca1b829ecd47e98cc9b0544c7aa874e755)) ## [3.12.0](https://github.com/eggjs/egg/compare/v3.11.1...v3.12.0) (2023-01-04) - ### Features -* siteFile favicon config support async function type ([#5114](https://github.com/eggjs/egg/issues/5114)) ([667684f](https://github.com/eggjs/egg/commit/667684f79d8485ee9d9a03bf99077fa2dfef5507)) +- siteFile favicon config support async function type ([#5114](https://github.com/eggjs/egg/issues/5114)) ([667684f](https://github.com/eggjs/egg/commit/667684f79d8485ee9d9a03bf99077fa2dfef5507)) ## [3.11.1](https://github.com/eggjs/egg/compare/v3.11.0...v3.11.1) (2023-01-03) - ### Bug Fixes -* remove duplicate identifier ssrf ([#5113](https://github.com/eggjs/egg/issues/5113)) ([2b407eb](https://github.com/eggjs/egg/commit/2b407ebce9112d96e5e8a452eef09bcc70496e92)) +- remove duplicate identifier ssrf ([#5113](https://github.com/eggjs/egg/issues/5113)) ([2b407eb](https://github.com/eggjs/egg/commit/2b407ebce9112d96e5e8a452eef09bcc70496e92)) ## [3.11.0](https://github.com/eggjs/egg/compare/v3.10.0...v3.11.0) (2023-01-02) - ### Features -* add ssrf declaration ([#4687](https://github.com/eggjs/egg/issues/4687)) ([b1414f2](https://github.com/eggjs/egg/commit/b1414f2c749da5ab9bf07abf26ff75eac0b9cb73)) +- add ssrf declaration ([#4687](https://github.com/eggjs/egg/issues/4687)) ([b1414f2](https://github.com/eggjs/egg/commit/b1414f2c749da5ab9bf07abf26ff75eac0b9cb73)) ## [3.10.0](https://github.com/eggjs/egg/compare/v3.9.2...v3.10.0) (2023-01-02) - ### Features -* use egg-core@5 ([#5111](https://github.com/eggjs/egg/issues/5111)) ([7b8edbf](https://github.com/eggjs/egg/commit/7b8edbf322ed59c76ce3a85cd4595605d743fb80)) +- use egg-core@5 ([#5111](https://github.com/eggjs/egg/issues/5111)) ([7b8edbf](https://github.com/eggjs/egg/commit/7b8edbf322ed59c76ce3a85cd4595605d743fb80)) ## [3.9.2](https://github.com/eggjs/egg/compare/v3.9.1...v3.9.2) (2022-12-21) - ### Bug Fixes -* currentContext typo ([#5107](https://github.com/eggjs/egg/issues/5107)) ([713a081](https://github.com/eggjs/egg/commit/713a081475189ef6d00c85a559849ff97f824d11)) +- currentContext typo ([#5107](https://github.com/eggjs/egg/issues/5107)) ([713a081](https://github.com/eggjs/egg/commit/713a081475189ef6d00c85a559849ff97f824d11)) ## [3.9.1](https://github.com/eggjs/egg/compare/v3.9.0...v3.9.1) (2022-12-18) - ### Bug Fixes -* Enable auto npm release workflow ([#5102](https://github.com/eggjs/egg/issues/5102)) ([13bbe6c](https://github.com/eggjs/egg/commit/13bbe6c24e1c8160ae629e12c81e30e27b6c3dba)) +- Enable auto npm release workflow ([#5102](https://github.com/eggjs/egg/issues/5102)) ([13bbe6c](https://github.com/eggjs/egg/commit/13bbe6c24e1c8160ae629e12c81e30e27b6c3dba)) ## [3.9.1](https://github.com/eggjs/egg/compare/v3.9.0...v3.9.1) (2022-12-18) - ### Bug Fixes -* Enable auto npm release workflow ([#5102](https://github.com/eggjs/egg/issues/5102)) ([13bbe6c](https://github.com/eggjs/egg/commit/13bbe6c24e1c8160ae629e12c81e30e27b6c3dba)) +- Enable auto npm release workflow ([#5102](https://github.com/eggjs/egg/issues/5102)) ([13bbe6c](https://github.com/eggjs/egg/commit/13bbe6c24e1c8160ae629e12c81e30e27b6c3dba)) --- @@ -258,1825 +225,1828 @@ ### Notable Changes -* **features** - * 📦 NEW: Run async function in the anonymous context scope +- **features** + - 📦 NEW: Run async function in the anonymous context scope ```js - await app.runInAnonymousContextScope(async ctx => { + await app.runInAnonymousContextScope(async (ctx) => { // run with anonymous ctx here }); ``` ### Commits - * [[`af1206904`](http://github.com/eggjs/egg/commit/af12069041c1ea11217688c9c17d3712a44d3422)] - chore: update workflow for gh-pages (#5098) (Suyi <>) - * [[`344139e47`](http://github.com/eggjs/egg/commit/344139e4759f56ab2beca2e2a5c2783160396ba9)] - 🐛 FIX: Typo on HttpClient request (#5097) (fengmk2 <>) - * [[`1021faf78`](http://github.com/eggjs/egg/commit/1021faf78e5f23fa366c0034a38f81b0f361e9ec)] - 👌 IMPROVE: Keep more compatible d.ts on httpclient request (#5092) (fengmk2 <>) - * [[`9d6acfd7c`](http://github.com/eggjs/egg/commit/9d6acfd7c3266ae6a56e45cb7a72473d628f6e16)] - 📦 NEW: Run async function in the anonymous context scope (#5094) (fengmk2 <>) +- [[`af1206904`](http://github.com/eggjs/egg/commit/af12069041c1ea11217688c9c17d3712a44d3422)] - chore: update workflow for gh-pages (#5098) (Suyi <>) +- [[`344139e47`](http://github.com/eggjs/egg/commit/344139e4759f56ab2beca2e2a5c2783160396ba9)] - 🐛 FIX: Typo on HttpClient request (#5097) (fengmk2 <>) +- [[`1021faf78`](http://github.com/eggjs/egg/commit/1021faf78e5f23fa366c0034a38f81b0f361e9ec)] - 👌 IMPROVE: Keep more compatible d.ts on httpclient request (#5092) (fengmk2 <>) +- [[`9d6acfd7c`](http://github.com/eggjs/egg/commit/9d6acfd7c3266ae6a56e45cb7a72473d628f6e16)] - 📦 NEW: Run async function in the anonymous context scope (#5094) (fengmk2 <>) ## 2022-12-12, Version 3.8.0 @fengmk2 ### Notable Changes -* **features** - * Upgrade egg-schedule@4 to support `app.currentContext` on scheduler +- **features** + - Upgrade egg-schedule@4 to support `app.currentContext` on scheduler ### Commits - * [[`75d025b24`](http://github.com/eggjs/egg/commit/75d025b24e5e3016f2df84e2ba1901f42156c0b7)] - 👌 IMPROVE: Upgrade egg-schedule to v4 (#5088) (fengmk2 <>) +- [[`75d025b24`](http://github.com/eggjs/egg/commit/75d025b24e5e3016f2df84e2ba1901f42156c0b7)] - 👌 IMPROVE: Upgrade egg-schedule to v4 (#5088) (fengmk2 <>) ## 2022-12-11, Version 3.7.0 @fengmk2 ### Notable Changes -* **features** - * 📦 NEW: Set `config.logger.enableFastContextLogger = true` to enable faster context logger +- **features** + - 📦 NEW: Set `config.logger.enableFastContextLogger = true` to enable faster context logger ### Commits - * [[`e94c7df63`](http://github.com/eggjs/egg/commit/e94c7df63e1812da672dbaf7200e652cc4537c7b)] - 📦 NEW: Upgrade egg-logger v3 to enable localStorage (#5085) (fengmk2 <>) - * [[`c76e16cf7`](http://github.com/eggjs/egg/commit/c76e16cf7fb67d5f2c1b19252e01a5e3fed9cf96)] - 📖 DOC: Use @eggjs/tsconfig for tsconfig.json (#5066) (fengmk2 <>) +- [[`e94c7df63`](http://github.com/eggjs/egg/commit/e94c7df63e1812da672dbaf7200e652cc4537c7b)] - 📦 NEW: Upgrade egg-logger v3 to enable localStorage (#5085) (fengmk2 <>) +- [[`c76e16cf7`](http://github.com/eggjs/egg/commit/c76e16cf7fb67d5f2c1b19252e01a5e3fed9cf96)] - 📖 DOC: Use @eggjs/tsconfig for tsconfig.json (#5066) (fengmk2 <>) ## 2022-12-09, Version 3.6.0 @fengmk2 ### Notable Changes -* **features** - * 🚀🚀🚀 Support `app.ctxStorage` and `app.currentContext` to get current execute ctx, see [koa#1455](https://github.com/koajs/koa/pull/1455) +- **features** + - 🚀🚀🚀 Support `app.ctxStorage` and `app.currentContext` to get current execute ctx, see [koa#1455](https://github.com/koajs/koa/pull/1455) ### Commits - * [[`bf36904e0`](http://github.com/eggjs/egg/commit/bf36904e0fb1d4477ebb7068dd8ad6726d29182f)] - 📦 NEW: Add ctxStorage and currentContext d.ts (#5079) (fengmk2 <>) - * [[`c68992ab7`](http://github.com/eggjs/egg/commit/c68992ab71b854f825df0ff3ea4b82e7666ec828)] - chore: ignore gp-pages branch while deploying preview (#5077) (Suyi <>) - * [[`13906825b`](http://github.com/eggjs/egg/commit/13906825bc3fab260aa0dd8888ce9fd19f2f70c5)] - chore: use actions to deploy vercel project (#5076) (Suyi <>) - * [[`5d825bb59`](http://github.com/eggjs/egg/commit/5d825bb59ed691bd45c3a8b2f6c222496910e250)] - docs: update communite links (#5073) (Suyi <>) +- [[`bf36904e0`](http://github.com/eggjs/egg/commit/bf36904e0fb1d4477ebb7068dd8ad6726d29182f)] - 📦 NEW: Add ctxStorage and currentContext d.ts (#5079) (fengmk2 <>) +- [[`c68992ab7`](http://github.com/eggjs/egg/commit/c68992ab71b854f825df0ff3ea4b82e7666ec828)] - chore: ignore gp-pages branch while deploying preview (#5077) (Suyi <>) +- [[`13906825b`](http://github.com/eggjs/egg/commit/13906825bc3fab260aa0dd8888ce9fd19f2f70c5)] - chore: use actions to deploy vercel project (#5076) (Suyi <>) +- [[`5d825bb59`](http://github.com/eggjs/egg/commit/5d825bb59ed691bd45c3a8b2f6c222496910e250)] - docs: update communite links (#5073) (Suyi <>) ## 2022-11-28, Version 3.5.1 @killagu ### Notable Changes -* **fixes** - * Dump `config/timing` when app start timeout +- **fixes** + - Dump `config/timing` when app start timeout ### Commits - * [[`c859506a0`](http://github.com/eggjs/egg/commit/c859506a094181f5f45db16a8501daaaea56b3d3)] - fix: dump config/timing when timeout (#5069) (killa <>) +- [[`c859506a0`](http://github.com/eggjs/egg/commit/c859506a094181f5f45db16a8501daaaea56b3d3)] - fix: dump config/timing when timeout (#5069) (killa <>) ## 2022-11-15, Version 3.5.0 @fengmk2 ### Notable Changes -* **features** - * Auto disable cluster-client heartbeat checker on debug mode +- **features** + - Auto disable cluster-client heartbeat checker on debug mode ### Commits - * [[`6de5cba5d`](http://github.com/eggjs/egg/commit/6de5cba5d0d02d09e9e6ee71f9e7b1cb3d65c24e)] - feat: disable cluster-client heartbeat on debug mode (#5059) (sinkhaha <<1468709106@qq.com>>) +- [[`6de5cba5d`](http://github.com/eggjs/egg/commit/6de5cba5d0d02d09e9e6ee71f9e7b1cb3d65c24e)] - feat: disable cluster-client heartbeat on debug mode (#5059) (sinkhaha <<1468709106@qq.com>>) ## 2022-11-07, Version 3.4.0 @fengmk2 ### Notable Changes -* **features** - * Upgrade egg-cluster v2 to support worker_threads start mode - * Drop httpclient callback and thunk style, a breaking change to egg@2 - * Print warnning log when boot action takes more than 5000ms - * Don't need to patch keep-alive header on Node.js >= 14.20.0 +- **features** + - Upgrade egg-cluster v2 to support worker_threads start mode + - Drop httpclient callback and thunk style, a breaking change to egg@2 + - Print warnning log when boot action takes more than 5000ms + - Don't need to patch keep-alive header on Node.js >= 14.20.0 ### Commits - * [[`2b5f289bb`](http://github.com/eggjs/egg/commit/2b5f289bba3bd14c2867136b5dcbf3bed5cfdf9e)] - 📦 NEW: Use egg-cluster v2 (#5055) (fengmk2 <>) - * [[`610a39e7f`](http://github.com/eggjs/egg/commit/610a39e7f41a17a2123705691d6c1bfdc3e12f88)] - 👌 IMPROVE: Drop httpclient callback and thunk style (#5052) (fengmk2 <>) - * [[`3a941d669`](http://github.com/eggjs/egg/commit/3a941d669cc1d2c12a2caad4dd24492e98444348)] - 👌 IMPROVE: Print warnning log when boot action takes more than 5000ms (#5049) (fengmk2 <>) - * [[`d820b739b`](http://github.com/eggjs/egg/commit/d820b739b95207bdea8c9b4c3da0f5059bc0113c)] - 👌 IMPROVE: Don't need to patch keep-alive header on Node.js >= 14.20.0 (#5051) (fengmk2 <>) - * [[`6ac4cdbfb`](http://github.com/eggjs/egg/commit/6ac4cdbfbb35905f6f315f51122c1badcb913b5c)] - 🤖 TEST: Add Node.js 19 ci runner (#5050) (fengmk2 <>) - * [[`d05cc015e`](http://github.com/eggjs/egg/commit/d05cc015e4a748bf41a4dbf46e978d1f4ad44954)] - docs: fix Application description (#5044) (ldc-37 <<34739463+ldc-37@users.noreply.github.com>>) +- [[`2b5f289bb`](http://github.com/eggjs/egg/commit/2b5f289bba3bd14c2867136b5dcbf3bed5cfdf9e)] - 📦 NEW: Use egg-cluster v2 (#5055) (fengmk2 <>) +- [[`610a39e7f`](http://github.com/eggjs/egg/commit/610a39e7f41a17a2123705691d6c1bfdc3e12f88)] - 👌 IMPROVE: Drop httpclient callback and thunk style (#5052) (fengmk2 <>) +- [[`3a941d669`](http://github.com/eggjs/egg/commit/3a941d669cc1d2c12a2caad4dd24492e98444348)] - 👌 IMPROVE: Print warnning log when boot action takes more than 5000ms (#5049) (fengmk2 <>) +- [[`d820b739b`](http://github.com/eggjs/egg/commit/d820b739b95207bdea8c9b4c3da0f5059bc0113c)] - 👌 IMPROVE: Don't need to patch keep-alive header on Node.js >= 14.20.0 (#5051) (fengmk2 <>) +- [[`6ac4cdbfb`](http://github.com/eggjs/egg/commit/6ac4cdbfbb35905f6f315f51122c1badcb913b5c)] - 🤖 TEST: Add Node.js 19 ci runner (#5050) (fengmk2 <>) +- [[`d05cc015e`](http://github.com/eggjs/egg/commit/d05cc015e4a748bf41a4dbf46e978d1f4ad44954)] - docs: fix Application description (#5044) (ldc-37 <<34739463+ldc-37@users.noreply.github.com>>) ## 2022-09-28, Version 3.3.3 @fengmk2 ### Notable Changes -* **fixes** - * Allow override HttpClientNext +- **fixes** + - Allow override HttpClientNext ### Commits - * [[`7ee19e840`](http://github.com/eggjs/egg/commit/7ee19e8402b1d23ecdc1791e044a1902049e14dd)] - 🐛 FIX: Allow override HttpClientNext (#5037) (fengmk2 <>) + +- [[`7ee19e840`](http://github.com/eggjs/egg/commit/7ee19e8402b1d23ecdc1791e044a1902049e14dd)] - 🐛 FIX: Allow override HttpClientNext (#5037) (fengmk2 <>) ## 2022-09-27, Version 3.3.2 @atian25 ### Notable Changes -* **fixes** - * update multipart 3.1.0, https://github.com/eggjs/egg-multipart/pull/56 +- **fixes** + - update multipart 3.1.0, https://github.com/eggjs/egg-multipart/pull/56 ### Commits - * [[`201bfa749`](http://github.com/eggjs/egg/commit/201bfa7492920aafad71b7845e5cc6eaef69f8bc)] - fix: update multipart 3.1.0 (#5034) (TZ | 天猪 <>) +- [[`201bfa749`](http://github.com/eggjs/egg/commit/201bfa7492920aafad71b7845e5cc6eaef69f8bc)] - fix: update multipart 3.1.0 (#5034) (TZ | 天猪 <>) ## 2022-09-26, Version 3.3.1 @fengmk2 ### Notable Changes -* **fixes** - * fallback egg-multipart@2 to support filename with non-ASCII characters -### Commits +- **fixes** + - fallback egg-multipart@2 to support filename with non-ASCII characters - * [[`acadb28e2`](http://github.com/eggjs/egg/commit/acadb28e2814b0b91828e0766673f199d7767f3a)] - fix: fallback egg-multipart to v2 (#5032) (fengmk2 <>) +### Commits +- [[`acadb28e2`](http://github.com/eggjs/egg/commit/acadb28e2814b0b91828e0766673f199d7767f3a)] - fix: fallback egg-multipart to v2 (#5032) (fengmk2 <>) ## 2022-09-23, Version 3.3.0 @fengmk2 ### Notable Changes -* **features** - * Support config `serverGracefulIgnoreCode` to ignore error avoid process exit when uncatch error emit - See https://github.com/node-modules/graceful/pull/13 +- **features** + - Support config `serverGracefulIgnoreCode` to ignore error avoid process exit when uncatch error emit + See https://github.com/node-modules/graceful/pull/13 + ### Commits - * [[`a0761d65f`](http://github.com/eggjs/egg/commit/a0761d65f5df1002853c169efedab969636247d3)] - feat(graceful): support serverGracefulIgnoreCode (#5027) (hyj1991 <>) - * [[`8b8dd3be9`](http://github.com/eggjs/egg/commit/8b8dd3be95bb53ad3c732b8bc9c20566021e955f)] - chore: remove jsdoc and disable vercel comment (#5026) (Suyi <>) - * [[`f4225339f`](http://github.com/eggjs/egg/commit/f4225339f6235f78fe53d34d1eb0993faa410b36)] - test: fix ci (#5025) (TZ | 天猪 <>) - * [[`5de994b9c`](http://github.com/eggjs/egg/commit/5de994b9c4cd17f9ecd4d4083c20b29f399a9e40)] - chore: fix action for gh-pages (#5024) (Suyi <>) +- [[`a0761d65f`](http://github.com/eggjs/egg/commit/a0761d65f5df1002853c169efedab969636247d3)] - feat(graceful): support serverGracefulIgnoreCode (#5027) (hyj1991 <>) +- [[`8b8dd3be9`](http://github.com/eggjs/egg/commit/8b8dd3be95bb53ad3c732b8bc9c20566021e955f)] - chore: remove jsdoc and disable vercel comment (#5026) (Suyi <>) +- [[`f4225339f`](http://github.com/eggjs/egg/commit/f4225339f6235f78fe53d34d1eb0993faa410b36)] - test: fix ci (#5025) (TZ | 天猪 <>) +- [[`5de994b9c`](http://github.com/eggjs/egg/commit/5de994b9c4cd17f9ecd4d4083c20b29f399a9e40)] - chore: fix action for gh-pages (#5024) (Suyi <>) ## 2022-09-21, Version 3.2.0 @fengmk2 ### Notable Changes **features** - * [[`733d66989`](http://github.com/eggjs/egg/commit/733d66989d1f8657ce55b6032944188da635b8f0)] - feat: update egg-multipart 2.x -> 3.x (#5023) (TZ | 天猪 <>) - * [[`2ffb37ab5`](http://github.com/eggjs/egg/commit/2ffb37ab59395c9b14f153f91abb9f816a5e98ea)] - feat: Support urllib@3 (#5000) (fengmk2 <>) + +- [[`733d66989`](http://github.com/eggjs/egg/commit/733d66989d1f8657ce55b6032944188da635b8f0)] - feat: update egg-multipart 2.x -> 3.x (#5023) (TZ | 天猪 <>) +- [[`2ffb37ab5`](http://github.com/eggjs/egg/commit/2ffb37ab59395c9b14f153f91abb9f816a5e98ea)] - feat: Support urllib@3 (#5000) (fengmk2 <>) **others** - * [[`485781389`](http://github.com/eggjs/egg/commit/485781389e548ff0cf1eb107fea93c1bb01170d7)] - docs: update the version of the required Node (#5021) (Maledong <>) - * [[`bbd0e432e`](http://github.com/eggjs/egg/commit/bbd0e432e52832cc7a3d4b26a0141d7eb02e3793)] - chore: change the templates of bug/suggestion report (#5019) (Maledong <>) - * [[`2c5ba484a`](http://github.com/eggjs/egg/commit/2c5ba484a2dd8f214b9cdb53aa952688bc54cb2b)] - 🐛 FIX: Add config.httpclient.useHttpClientNext defined (#5001) (fengmk2 <>) + +- [[`485781389`](http://github.com/eggjs/egg/commit/485781389e548ff0cf1eb107fea93c1bb01170d7)] - docs: update the version of the required Node (#5021) (Maledong <>) +- [[`bbd0e432e`](http://github.com/eggjs/egg/commit/bbd0e432e52832cc7a3d4b26a0141d7eb02e3793)] - chore: change the templates of bug/suggestion report (#5019) (Maledong <>) +- [[`2c5ba484a`](http://github.com/eggjs/egg/commit/2c5ba484a2dd8f214b9cdb53aa952688bc54cb2b)] - 🐛 FIX: Add config.httpclient.useHttpClientNext defined (#5001) (fengmk2 <>) ## 2022-08-28, Version 3.1.0 @fengmk2 ### Notable Changes -* **features** - * Support urllib@3 by `config.httpclient.useHttpClientNext = true`, see [#4847](https://github.com/eggjs/egg/issues/4847) +- **features** + - Support urllib@3 by `config.httpclient.useHttpClientNext = true`, see [#4847](https://github.com/eggjs/egg/issues/4847) ### Commits - * [[`2c5ba484a`](http://github.com/eggjs/egg/commit/2c5ba484a2dd8f214b9cdb53aa952688bc54cb2b)] - 🐛 FIX: Add config.httpclient.useHttpClientNext defined (#5001) (fengmk2 <>) - * [[`2ffb37ab5`](http://github.com/eggjs/egg/commit/2ffb37ab59395c9b14f153f91abb9f816a5e98ea)] - feat: Support urllib@3 (#5000) (fengmk2 <>) + +- [[`2c5ba484a`](http://github.com/eggjs/egg/commit/2c5ba484a2dd8f214b9cdb53aa952688bc54cb2b)] - 🐛 FIX: Add config.httpclient.useHttpClientNext defined (#5001) (fengmk2 <>) +- [[`2ffb37ab5`](http://github.com/eggjs/egg/commit/2ffb37ab59395c9b14f153f91abb9f816a5e98ea)] - feat: Support urllib@3 (#5000) (fengmk2 <>) ## 2022-08-21, Version 3.0.0 @fengmk2 **features** - * Drop Node.js 8, 10, 12 supports, this release is a LTS version for egg@2, see https://github.com/eggjs/egg/issues/3644#issuecomment-1221460692 + +- Drop Node.js 8, 10, 12 supports, this release is a LTS version for egg@2, see https://github.com/eggjs/egg/issues/3644#issuecomment-1221460692 ## 2022-06-17, Version 2.36.0 @atian25 **features** - * [[`e0b93e023`](http://github.com/eggjs/egg/commit/e0b93e023e1258c4037c68dacfc41fc304602bbc)] - feat: should log unfinished timing item (#4968) (TZ | 天猪 <>) + +- [[`e0b93e023`](http://github.com/eggjs/egg/commit/e0b93e023e1258c4037c68dacfc41fc304602bbc)] - feat: should log unfinished timing item (#4968) (TZ | 天猪 <>) **others** - * [[`7f1689f9f`](http://github.com/eggjs/egg/commit/7f1689f9fbd286bde3b8b5aebf86af09a599359c)] - chore: typo CSRF on router.md (#4962) (Homyee King <>) - * [[`e31c09c20`](http://github.com/eggjs/egg/commit/e31c09c2001b15fbc2431f4c36f6e59da5e3ebca)] - chore: fix some comments (#4937) (Maledong <>) - * [[`b0c17fdd0`](http://github.com/eggjs/egg/commit/b0c17fdd02512f743786203c326dc86be636f9a6)] - chore: remove git.io (#4940) (Baoshuo Ren <>) - * [[`12755e275`](http://github.com/eggjs/egg/commit/12755e27555b8f84a745c319c89b1c4d75ae3f78)] - test: Create codeql-analysis.yml (#4935) (fengmk2 <>) - * [[`8078917fd`](http://github.com/eggjs/egg/commit/8078917fd66c41d21b0f2c738f77cc7916edfaca)] - chore: package upgrade and unittest fixture (#4933) (Maledong <>) - * [[`a5a358ceb`](http://github.com/eggjs/egg/commit/a5a358cebc78734d45a450a641913ae242c5dc70)] - chore: fix contributors badges on README.md (#4930) (XiaoRui <>) + +- [[`7f1689f9f`](http://github.com/eggjs/egg/commit/7f1689f9fbd286bde3b8b5aebf86af09a599359c)] - chore: typo CSRF on router.md (#4962) (Homyee King <>) +- [[`e31c09c20`](http://github.com/eggjs/egg/commit/e31c09c2001b15fbc2431f4c36f6e59da5e3ebca)] - chore: fix some comments (#4937) (Maledong <>) +- [[`b0c17fdd0`](http://github.com/eggjs/egg/commit/b0c17fdd02512f743786203c326dc86be636f9a6)] - chore: remove git.io (#4940) (Baoshuo Ren <>) +- [[`12755e275`](http://github.com/eggjs/egg/commit/12755e27555b8f84a745c319c89b1c4d75ae3f78)] - test: Create codeql-analysis.yml (#4935) (fengmk2 <>) +- [[`8078917fd`](http://github.com/eggjs/egg/commit/8078917fd66c41d21b0f2c738f77cc7916edfaca)] - chore: package upgrade and unittest fixture (#4933) (Maledong <>) +- [[`a5a358ceb`](http://github.com/eggjs/egg/commit/a5a358cebc78734d45a450a641913ae242c5dc70)] - chore: fix contributors badges on README.md (#4930) (XiaoRui <>) ## 2022-04-01, Version 2.35.0 @mansonchor **features** - * [[`c1313f5ef`](http://github.com/eggjs/egg/commit/c1313f5ef960e5aaad7f04adb6665679f2ec10e2)] - feat: dumpConfig add appInfo (#4917) (mansonchor.github.com <>) + +- [[`c1313f5ef`](http://github.com/eggjs/egg/commit/c1313f5ef960e5aaad7f04adb6665679f2ec10e2)] - feat: dumpConfig add appInfo (#4917) (mansonchor.github.com <>) **others** - * [[`4e5309188`](http://github.com/eggjs/egg/commit/4e5309188a60393435d5ab2df65ca67186f31035)] - test: add ChainAlert action (#4908) (fengmk2 <>) + +- [[`4e5309188`](http://github.com/eggjs/egg/commit/4e5309188a60393435d5ab2df65ca67186f31035)] - test: add ChainAlert action (#4908) (fengmk2 <>) ## 2022-03-16, Version 2.34.0 **features** - * [[`caacd09c3`](http://github.com/eggjs/egg/commit/caacd09c38aae03fc291febbb97a43c8ecbdc221)] - feat: siteFile support custom control-cache (#4902) (binginsist <>) + +- [[`caacd09c3`](http://github.com/eggjs/egg/commit/caacd09c38aae03fc291febbb97a43c8ecbdc221)] - feat: siteFile support custom control-cache (#4902) (binginsist <>) **others** - * [[`f97fe4a8c`](http://github.com/eggjs/egg/commit/f97fe4a8c8c0b5f8c097055213f9e7177b9ab2dd)] - test: change error code assert (#4907) (fengmk2 <>) - * [[`a7aa7f37d`](http://github.com/eggjs/egg/commit/a7aa7f37d901afd4c26a2a9aa57fe938b2109e94)] - docs: typo fix on deployment.zh-CN.md (#4906) (Krryxa <>) - * [[`d3fe13aa2`](http://github.com/eggjs/egg/commit/d3fe13aa25065995cfa9d78461be80194176f183)] - docs: typo fix on security.zh-CN.md (#4905) (Krryxa <>) - * [[`2dc723129`](http://github.com/eggjs/egg/commit/2dc723129614bd727e86871ae3e7cfc60166dd81)] - docs: use egg brand color for site (#4900) (Peach <>) - * [[`11bbd8527`](http://github.com/eggjs/egg/commit/11bbd852731b1583cae5a5d519baa20960c0521d)] - docs: enhance (#4884) (Suyi <>) - * [[`76d014bd5`](http://github.com/eggjs/egg/commit/76d014bd583c6d0b9b9f40ac2e6e7ba9dd66e8ed)] - docs: update node version (#4886) (lxinr <<33972246+lxinr@users.noreply.github.com>>) - * [[`9003cb5ad`](http://github.com/eggjs/egg/commit/9003cb5ad370d0c07b2baee88f3b25c597ac3929)] - docs: update https://registry.npm.taobao.org to https://registry.npmmirror.com (#4881) (Non-Official NPM Mirror Bot <<99484857+npmmirror@users.noreply.github.com>>) - * [[`b47409770`](http://github.com/eggjs/egg/commit/b47409770d76f03eb1ea0476be9e00207186c42e)] - docs: dumi (#4879) (Suyi <>) - * [[`56816dbc5`](http://github.com/eggjs/egg/commit/56816dbc59dbb1a4973ca60130c9ff3f5be8b2da)] - docs (sequelize): Changed `config.sequelize` to `exports.sequelize` in configuration part (#4873) (Aelita <<45784210+xsjcTony@users.noreply.github.com>>) - * [[`20842f9c2`](http://github.com/eggjs/egg/commit/20842f9c216ed538924936163b7ed18437c54cd7)] - docs: Add license scan report and status (#4880) (fossabot <>) + +- [[`f97fe4a8c`](http://github.com/eggjs/egg/commit/f97fe4a8c8c0b5f8c097055213f9e7177b9ab2dd)] - test: change error code assert (#4907) (fengmk2 <>) +- [[`a7aa7f37d`](http://github.com/eggjs/egg/commit/a7aa7f37d901afd4c26a2a9aa57fe938b2109e94)] - docs: typo fix on deployment.zh-CN.md (#4906) (Krryxa <>) +- [[`d3fe13aa2`](http://github.com/eggjs/egg/commit/d3fe13aa25065995cfa9d78461be80194176f183)] - docs: typo fix on security.zh-CN.md (#4905) (Krryxa <>) +- [[`2dc723129`](http://github.com/eggjs/egg/commit/2dc723129614bd727e86871ae3e7cfc60166dd81)] - docs: use egg brand color for site (#4900) (Peach <>) +- [[`11bbd8527`](http://github.com/eggjs/egg/commit/11bbd852731b1583cae5a5d519baa20960c0521d)] - docs: enhance (#4884) (Suyi <>) +- [[`76d014bd5`](http://github.com/eggjs/egg/commit/76d014bd583c6d0b9b9f40ac2e6e7ba9dd66e8ed)] - docs: update node version (#4886) (lxinr <<33972246+lxinr@users.noreply.github.com>>) +- [[`9003cb5ad`](http://github.com/eggjs/egg/commit/9003cb5ad370d0c07b2baee88f3b25c597ac3929)] - docs: update https://registry.npm.taobao.org to https://registry.npmmirror.com (#4881) (Non-Official NPM Mirror Bot <<99484857+npmmirror@users.noreply.github.com>>) +- [[`b47409770`](http://github.com/eggjs/egg/commit/b47409770d76f03eb1ea0476be9e00207186c42e)] - docs: dumi (#4879) (Suyi <>) +- [[`56816dbc5`](http://github.com/eggjs/egg/commit/56816dbc59dbb1a4973ca60130c9ff3f5be8b2da)] - docs (sequelize): Changed `config.sequelize` to `exports.sequelize` in configuration part (#4873) (Aelita <<45784210+xsjcTony@users.noreply.github.com>>) +- [[`20842f9c2`](http://github.com/eggjs/egg/commit/20842f9c216ed538924936163b7ed18437c54cd7)] - docs: Add license scan report and status (#4880) (fossabot <>) ## 2021-12-07, Version 2.33.1 **features** - * [[`18dcadc1c`](http://github.com/eggjs/egg/commit/18dcadc1cf6c9837de605916a0d8b161a63e7218)] - feat: meta middleware x-readtime support performanceStarttime (#4827) (fengmk2 <>) + +- [[`18dcadc1c`](http://github.com/eggjs/egg/commit/18dcadc1cf6c9837de605916a0d8b161a63e7218)] - feat: meta middleware x-readtime support performanceStarttime (#4827) (fengmk2 <>) **others** - * [[`8659d4bc3`](http://github.com/eggjs/egg/commit/8659d4bc37e0652d66d04d2e5504fdc0ef2f7f7d)] - docs: update contributors (#4826) (Suyi <>) - * [[`4d18732c7`](http://github.com/eggjs/egg/commit/4d18732c79e44a84140df05e879b8b5f569c2b4b)] - chore: remove @types/urllib from autod (fengmk2 <>) + +- [[`8659d4bc3`](http://github.com/eggjs/egg/commit/8659d4bc37e0652d66d04d2e5504fdc0ef2f7f7d)] - docs: update contributors (#4826) (Suyi <>) +- [[`4d18732c7`](http://github.com/eggjs/egg/commit/4d18732c79e44a84140df05e879b8b5f569c2b4b)] - chore: remove @types/urllib from autod (fengmk2 <>) ## 2021-12-06, Version 2.33.0 **features** - * [[`0f6589e1d`](http://github.com/eggjs/egg/commit/0f6589e1dc9e538434eb1580327556d5aa264822)] - feat: support better logger timer in precise milliseconds (#4806) (fengmk2 <>) + +- [[`0f6589e1d`](http://github.com/eggjs/egg/commit/0f6589e1dc9e538434eb1580327556d5aa264822)] - feat: support better logger timer in precise milliseconds (#4806) (fengmk2 <>) ## 2021-11-15, Version 2.32.0 @atian25 ### Notable Changes -* **features** - * handle ENETUNREACH error on httpclient +- **features** + - handle ENETUNREACH error on httpclient ### Commits - * [[`189c47804`](http://github.com/eggjs/egg/commit/189c478048d820b7b1a6ba6e8bce3444604876ff)] - feat: handle ENETUNREACH error on httpclient (#4792) (fengmk2 <>) - +- [[`189c47804`](http://github.com/eggjs/egg/commit/189c478048d820b7b1a6ba6e8bce3444604876ff)] - feat: handle ENETUNREACH error on httpclient (#4792) (fengmk2 <>) ## 2021-10-18, Version 2.31.0 @killagu ### Notable Changes -* **typing** - * support ssrf typing in config +- **typing** + - support ssrf typing in config ### Commits -* [[`debfda7ab`](https://github.com/eggjs/egg/commit/debfda7ab38f4893b6f122abfbf3e5288af1441e)] - feat(config): support ssrf field in security config. (#4778) (Jasin Yip <>) +- [[`debfda7ab`](https://github.com/eggjs/egg/commit/debfda7ab38f4893b6f122abfbf3e5288af1441e)] - feat(config): support ssrf field in security config. (#4778) (Jasin Yip <>) ## 2021-08-09, Version 2.30.0 @mansonchor ### Notable Changes -* **features** - * support disableDNSCache in one request even though config set to `enableDNSCache: true` +- **features** + - support disableDNSCache in one request even though config set to `enableDNSCache: true` -* **docs** - * update ts docs, add missing zh-CN doc - * typo fix +- **docs** + - update ts docs, add missing zh-CN doc + - typo fix ### Commits - * [[`13dd55076`](https://github.com/eggjs/egg.git/commit/13dd5507694a57a11e12d1ac6f71ba4a562d88c0)] - feat: support disableDNSCache by request args handle (#4728) (mansonchor.github.com <>) - * [[`1b4fde454`](https://github.com/eggjs/egg.git/commit/1b4fde454d2d61200a8b066ba841ad6d81b5b69d)] - unittest: rename and remove some useless tests (#4705) (Maledong <>) - * [[`156980d36`](https://github.com/eggjs/egg.git/commit/156980d369570531c1ef9cf842f02f513b56fe4a)] - doc: Typo fixture (#4707) (Maledong <>) - * [[`27aa49b59`](https://github.com/eggjs/egg.git/commit/27aa49b5945f08fa6b636479cf4cba7822e3af2d)] - doc: Typo fixture:「,」->「,」 (#4708) (陈煮酒 <<501205587@qq.com>>) - * [[`1f02a8d45`](https://github.com/eggjs/egg.git/commit/1f02a8d4560ca3334425e646c1ac87226aba3a63)] - doc: Add the missing zh-CN trans for typescript (#4703) (Maledong <<52018749+MaledongGit@users.noreply.github.com>>) - * [[`f5cf0d965`](https://github.com/eggjs/egg.git/commit/f5cf0d965fa4077da10e87f070e113496077872c)] - doc: "登陆" should be "登录" (#4697) (HOU Ce <<594965698@qq.com>>) - * [[`750558400`](https://github.com/eggjs/egg.git/commit/750558400e3bd5f39658dfcbedd4af7bc0bdda2a)] - docs: update ts docs (#4666) (吖猩 <>) - * [[`93d2b04b9`](https://github.com/eggjs/egg.git/commit/93d2b04b985145f27a39335300a78002a61da2a8)] - docs: fix loaderUpdate.md didReady example (#4652) (shadyzoz <>) +- [[`13dd55076`](https://github.com/eggjs/egg.git/commit/13dd5507694a57a11e12d1ac6f71ba4a562d88c0)] - feat: support disableDNSCache by request args handle (#4728) (mansonchor.github.com <>) +- [[`1b4fde454`](https://github.com/eggjs/egg.git/commit/1b4fde454d2d61200a8b066ba841ad6d81b5b69d)] - unittest: rename and remove some useless tests (#4705) (Maledong <>) +- [[`156980d36`](https://github.com/eggjs/egg.git/commit/156980d369570531c1ef9cf842f02f513b56fe4a)] - doc: Typo fixture (#4707) (Maledong <>) +- [[`27aa49b59`](https://github.com/eggjs/egg.git/commit/27aa49b5945f08fa6b636479cf4cba7822e3af2d)] - doc: Typo fixture:「,」->「,」 (#4708) (陈煮酒 <<501205587@qq.com>>) +- [[`1f02a8d45`](https://github.com/eggjs/egg.git/commit/1f02a8d4560ca3334425e646c1ac87226aba3a63)] - doc: Add the missing zh-CN trans for typescript (#4703) (Maledong <<52018749+MaledongGit@users.noreply.github.com>>) +- [[`f5cf0d965`](https://github.com/eggjs/egg.git/commit/f5cf0d965fa4077da10e87f070e113496077872c)] - doc: "登陆" should be "登录" (#4697) (HOU Ce <<594965698@qq.com>>) +- [[`750558400`](https://github.com/eggjs/egg.git/commit/750558400e3bd5f39658dfcbedd4af7bc0bdda2a)] - docs: update ts docs (#4666) (吖猩 <>) +- [[`93d2b04b9`](https://github.com/eggjs/egg.git/commit/93d2b04b985145f27a39335300a78002a61da2a8)] - docs: fix loaderUpdate.md didReady example (#4652) (shadyzoz <>) ## 2021-04-13, Version 2.29.4 @popomore ### Notable Changes -* **fixes** - * remove internal interval handler when close agent -* **docs** - * Added english doc to how-to-migrate-from-1.x, Thx @ZixiaoWang - * typo improvement +- **fixes** + - remove internal interval handler when close agent +- **docs** + - Added english doc to how-to-migrate-from-1.x, Thx @ZixiaoWang + - typo improvement ### Commits - * [[`ce234226b`](http://github.com/eggjs/egg/commit/ce234226bf0c43f03aedf727a7d195ae4175c01f)] - fix: remove internal interval handler when close agent (#4654) (Harry Chen <>) - * [[`6a6d68fb2`](http://github.com/eggjs/egg/commit/6a6d68fb228a3eae9b5cab3ba7afe0892d5e08ea)] - Typo fixture:制定 -> 指定 (#4639) (华晨 <>) - * [[`603c74b58`](http://github.com/eggjs/egg/commit/603c74b581d6b3a9ad80170335425b0876ffcb1f)] - docs: Added english doc to how-to-migrate-from-1.x (#4630) (Jacky Wang <>) - * [[`693df6066`](http://github.com/eggjs/egg/commit/693df60661735008e8a758258fc2df0bb9783f04)] - docs: fix schedule reference (#4556) (xuxu <>) - * [[`4ebbe8143`](http://github.com/eggjs/egg/commit/4ebbe814386102377870959129e831a3b20133c1)] - docs: fix typo (#4596) (suinia <>) +- [[`ce234226b`](http://github.com/eggjs/egg/commit/ce234226bf0c43f03aedf727a7d195ae4175c01f)] - fix: remove internal interval handler when close agent (#4654) (Harry Chen <>) +- [[`6a6d68fb2`](http://github.com/eggjs/egg/commit/6a6d68fb228a3eae9b5cab3ba7afe0892d5e08ea)] - Typo fixture:制定 -> 指定 (#4639) (华晨 <>) +- [[`603c74b58`](http://github.com/eggjs/egg/commit/603c74b581d6b3a9ad80170335425b0876ffcb1f)] - docs: Added english doc to how-to-migrate-from-1.x (#4630) (Jacky Wang <>) +- [[`693df6066`](http://github.com/eggjs/egg/commit/693df60661735008e8a758258fc2df0bb9783f04)] - docs: fix schedule reference (#4556) (xuxu <>) +- [[`4ebbe8143`](http://github.com/eggjs/egg/commit/4ebbe814386102377870959129e831a3b20133c1)] - docs: fix typo (#4596) (suinia <>) ## 2021-02-19, Version 2.29.3 @killa ### Notable Changes -* **fixes** - * fix ctx body typing +- **fixes** + - fix ctx body typing ### Commits - * [[`e9fba1b7b`](http://github.com/eggjs/egg/commit/e9fba1b7bbe3f54b023262aeb5487b31047e119e)] - fix: fix ctx body as any (#4613) (killa <>) + +- [[`e9fba1b7b`](http://github.com/eggjs/egg/commit/e9fba1b7bbe3f54b023262aeb5487b31047e119e)] - fix: fix ctx body as any (#4613) (killa <>) ## 2021-02-18, Version 2.29.2 @killa ### Notable Changes -* **fixes** - * fix query typing - * add overrideIgnore define +- **fixes** + - fix query typing + - add overrideIgnore define ### Commits - * [[`99682e4bd`](http://github.com/eggjs/egg/commit/99682e4bd5afe1697cab02001e919b967c264869)] - fix: fix query typing (#4611) (killa <>) - * [[`26017ee2e`](http://github.com/eggjs/egg/commit/26017ee2e49bd8a42b660baabe31284e00f81bcb)] - chore: fix comment typo at request.js (#4513) (Albert 理斯特 <>) - * [[`34048c275`](http://github.com/eggjs/egg/commit/34048c275afe1126716ef4265b667169e9866e53)] - fix: add overrideIgnore define (#4490) (kotot <<317643941@qq.com>>) - * [[`d652658d1`](http://github.com/eggjs/egg/commit/d652658d1205d0fbc73b4417c2ae54ee0a24f395)] - docs: d2 ads (#4508) (Suyi <>) +- [[`99682e4bd`](http://github.com/eggjs/egg/commit/99682e4bd5afe1697cab02001e919b967c264869)] - fix: fix query typing (#4611) (killa <>) +- [[`26017ee2e`](http://github.com/eggjs/egg/commit/26017ee2e49bd8a42b660baabe31284e00f81bcb)] - chore: fix comment typo at request.js (#4513) (Albert 理斯特 <>) +- [[`34048c275`](http://github.com/eggjs/egg/commit/34048c275afe1126716ef4265b667169e9866e53)] - fix: add overrideIgnore define (#4490) (kotot <<317643941@qq.com>>) +- [[`d652658d1`](http://github.com/eggjs/egg/commit/d652658d1205d0fbc73b4417c2ae54ee0a24f395)] - docs: d2 ads (#4508) (Suyi <>) ## 2020-10-19, Version 2.29.1 @atian25 ### Notable Changes -* **fixes** - * revert clear timing after ready, only disable - * won't set keep-alive header at Node.js ^12.19.0 || >=14.8.0 +- **fixes** + - revert clear timing after ready, only disable + - won't set keep-alive header at Node.js ^12.19.0 || >=14.8.0 ### Commits - * [[`9f653afe7`](http://github.com/eggjs/egg/commit/9f653afe790e0ead44109c68dfffb8353fdca56c)] - fix: remove clear timing && skip keep-alive after 12.19.0 (#4497) (TZ | 天猪 <>) - +- [[`9f653afe7`](http://github.com/eggjs/egg/commit/9f653afe790e0ead44109c68dfffb8353fdca56c)] - fix: remove clear timing && skip keep-alive after 12.19.0 (#4497) (TZ | 天猪 <>) ## 2020-09-23, Version 2.29.0 @atian25 ### Notable Changes -* **features** - * dumpconfig also dump disabled plugin +- **features** + - dumpconfig also dump disabled plugin -* **docs** - * csrf double cookie defense should enabled on all method - * test case for env.EGG_APP_CONFIG - * optimize multiple env configuration description +- **docs** + - csrf double cookie defense should enabled on all method + - test case for env.EGG_APP_CONFIG + - optimize multiple env configuration description ### Commits - * [[`cc80c6ab8`](http://github.com/eggjs/egg/commit/cc80c6ab86c71b1c9ea244065d4766297bfb6c17)] - feat: dumpconfig also dump disabled plugin (#4480) (TZ | 天猪 <>) - * [[`1d32771e5`](http://github.com/eggjs/egg/commit/1d32771e5aeb8fa8546ad8bfacf2f438973afae0)] - doc: csrf double cookie defense should enabled on all method (#3881) (Hongcai Deng <>) - * [[`504e4bebc`](http://github.com/eggjs/egg/commit/504e4bebcef03830be7c7432210b5b6b1de9d06b)] - test: for env.EGG_APP_CONFIG (#4468) (TZ | 天猪 <>) - * [[`ff4dfaa09`](http://github.com/eggjs/egg/commit/ff4dfaa098ad40ab7a0773c44d409829fcbb0e41)] - docs(config): optimize multiple env configuration description (#4406) (Andy <>) - * [[`b283791da`](http://github.com/eggjs/egg/commit/b283791dab3c86beb14506668e2aa3ef21cb78e6)] - docs: update badge to github action (#4463) (TZ | 天猪 <>) - +- [[`cc80c6ab8`](http://github.com/eggjs/egg/commit/cc80c6ab86c71b1c9ea244065d4766297bfb6c17)] - feat: dumpconfig also dump disabled plugin (#4480) (TZ | 天猪 <>) +- [[`1d32771e5`](http://github.com/eggjs/egg/commit/1d32771e5aeb8fa8546ad8bfacf2f438973afae0)] - doc: csrf double cookie defense should enabled on all method (#3881) (Hongcai Deng <>) +- [[`504e4bebc`](http://github.com/eggjs/egg/commit/504e4bebcef03830be7c7432210b5b6b1de9d06b)] - test: for env.EGG_APP_CONFIG (#4468) (TZ | 天猪 <>) +- [[`ff4dfaa09`](http://github.com/eggjs/egg/commit/ff4dfaa098ad40ab7a0773c44d409829fcbb0e41)] - docs(config): optimize multiple env configuration description (#4406) (Andy <>) +- [[`b283791da`](http://github.com/eggjs/egg/commit/b283791dab3c86beb14506668e2aa3ef21cb78e6)] - docs: update badge to github action (#4463) (TZ | 天猪 <>) ## 2020-09-08, Version 2.28.0 @atian25 ### Notable Changes -* **features** - * clear & disable timing after ready +- **features** + - clear & disable timing after ready -* **fixes** - * only set keep-alive header before Node.js 14.8.0 +- **fixes** + - only set keep-alive header before Node.js 14.8.0 -* **typings** - * Added missing types in HttpClientConfig - * export EggLogger/EggHttpClient/EggContextHttpClient +- **typings** + - Added missing types in HttpClientConfig + - export EggLogger/EggHttpClient/EggContextHttpClient -* **docs** - * fixed grammatical and spelling errors - * update compress url +- **docs** + - fixed grammatical and spelling errors + - update compress url ### Commits - * [[`b31b47df1`](http://github.com/eggjs/egg/commit/b31b47df10722bfac7ac13771db534f0200fc6ce)] - feat: clear & disable timing after ready (#4421) (TZ | 天猪 <>) - * [[`d25d32e58`](http://github.com/eggjs/egg/commit/d25d32e584b0bfd80f21cc522b91ac465f2852ac)] - fix: only set keep-alive header before Node.js 14.8.0 (#4457) (TZ | 天猪 <>) - * [[`a7ae46c84`](http://github.com/eggjs/egg/commit/a7ae46c847db07c0c4af1a85173bc4009d1219d9)] - type: Added missing types in HttpClientConfig (#4388) (Gcaufy <>) - * [[`064cc7a91`](http://github.com/eggjs/egg/commit/064cc7a91a2be89e39d72a833a1cb35cdcd8f201)] - docs: fixed grammatical and spelling errors (#4424) (Hridayesh Sharma <>) - * [[`95776d646`](http://github.com/eggjs/egg/commit/95776d6462080448e946c049f9ad4da4e9fc065e)] - docs: fix spelling mistakes and grammatical errors (#4423) (Hridayesh Sharma <>) - * [[`50976280f`](http://github.com/eggjs/egg/commit/50976280fcb19ce556ddc46f76da1f5fab46fa4a)] - docs: update compress url (#4415) (忽如寄 <<594613537@qq.com>>) +- [[`b31b47df1`](http://github.com/eggjs/egg/commit/b31b47df10722bfac7ac13771db534f0200fc6ce)] - feat: clear & disable timing after ready (#4421) (TZ | 天猪 <>) +- [[`d25d32e58`](http://github.com/eggjs/egg/commit/d25d32e584b0bfd80f21cc522b91ac465f2852ac)] - fix: only set keep-alive header before Node.js 14.8.0 (#4457) (TZ | 天猪 <>) +- [[`a7ae46c84`](http://github.com/eggjs/egg/commit/a7ae46c847db07c0c4af1a85173bc4009d1219d9)] - type: Added missing types in HttpClientConfig (#4388) (Gcaufy <>) +- [[`064cc7a91`](http://github.com/eggjs/egg/commit/064cc7a91a2be89e39d72a833a1cb35cdcd8f201)] - docs: fixed grammatical and spelling errors (#4424) (Hridayesh Sharma <>) +- [[`95776d646`](http://github.com/eggjs/egg/commit/95776d6462080448e946c049f9ad4da4e9fc065e)] - docs: fix spelling mistakes and grammatical errors (#4423) (Hridayesh Sharma <>) +- [[`50976280f`](http://github.com/eggjs/egg/commit/50976280fcb19ce556ddc46f76da1f5fab46fa4a)] - docs: update compress url (#4415) (忽如寄 <<594613537@qq.com>>) ## 2020-06-29, Version 2.27.0 @killa ### Notable Changes -* **typings** - * fix curl type - * export EggLogger/EggHttpClient/EggContextHttpClient +- **typings** + - fix curl type + - export EggLogger/EggHttpClient/EggContextHttpClient -* **docs** - * update docs about how to extends ctx.helper +- **docs** + - update docs about how to extends ctx.helper ### Commits - * [[`b5cc8b6e3`](http://github.com/eggjs/egg/commit/b5cc8b6e361b1ac2e7b4eb509f1e6486fe1dab13)] - fix(dts): fix curl type (#4312) (胡宇航 <<591765099@qq.com>>) - * [[`432128a80`](http://github.com/eggjs/egg/commit/432128a80aefdc8d11a6571da1ff35550e85fd66)] - type: export EggLogger/EggHttpClient/EggContextHttpClient (#4280) (killa <>) - * [[`eca6b04c1`](http://github.com/eggjs/egg/commit/eca6b04c1c50bc69c53f9910cc35bb7441c7cb02)] - docs:update docs about how to extends ctx.helper (#4362) (EasonQwQ <<750225883@qq.com>>) - +- [[`b5cc8b6e3`](http://github.com/eggjs/egg/commit/b5cc8b6e361b1ac2e7b4eb509f1e6486fe1dab13)] - fix(dts): fix curl type (#4312) (胡宇航 <<591765099@qq.com>>) +- [[`432128a80`](http://github.com/eggjs/egg/commit/432128a80aefdc8d11a6571da1ff35550e85fd66)] - type: export EggLogger/EggHttpClient/EggContextHttpClient (#4280) (killa <>) +- [[`eca6b04c1`](http://github.com/eggjs/egg/commit/eca6b04c1c50bc69c53f9910cc35bb7441c7cb02)] - docs:update docs about how to extends ctx.helper (#4362) (EasonQwQ <<750225883@qq.com>>) ## 2020-05-13, Version 2.26.1 @dead-horse ### Notable Changes -* **fixes** - * runInBackground always run after setImmediate +- **fixes** + - runInBackground always run after setImmediate -* **docs** - * imporve docs - * imporve typings +- **docs** + - imporve docs + - imporve typings ### Commits - * [[`9c67298d6`](http://github.com/eggjs/egg/commit/9c67298d69946d4ba0887c3648d3404e835c6902)] - test: run test on node 14 (#4272) (fengmk2 <>) - * [[`427a30a07`](http://github.com/eggjs/egg/commit/427a30a071d248cc2e5e15bb4bad35f3058e867f)] - test: make dnscache test case more stable (#4297) (Yiyu He <>) - * [[`64efd076b`](http://github.com/eggjs/egg/commit/64efd076bf9d937e36748f89bada6fce186913cd)] - fix: runInBackground always run after setImmediate (#4296) (Yiyu He <>) - * [[`69923977a`](http://github.com/eggjs/egg/commit/69923977a7e5c0825f2fc5c616852b0721411a0c)] - docs: Update doc for config of logger.consoleLevel (#4276) (xuxu <>) - * [[`7b6e4371c`](http://github.com/eggjs/egg/commit/7b6e4371c7367583627977a0ca4aa2ff66e28429)] - docs(typescript): Add --noEmit to unittest example code (#4250) (Ink <>) - * [[`3413e35fd`](http://github.com/eggjs/egg/commit/3413e35fd86408896e5c0b7e77ec2528ac08c9f9)] - chore: fix typo (#4234) (zoomdong <<1344492820@qq.com>>) - * [[`b4b9b50af`](http://github.com/eggjs/egg/commit/b4b9b50af1bb842e0138fc236d45882188698123)] - doc (socketio): fix packet middleware bug (#4204) (zfx <<502545703@qq.com>>) - * [[`2fcd605c6`](http://github.com/eggjs/egg/commit/2fcd605c6397480b0a5add9c11f7c7d071393de5)] - docs: update bodyParser types and doc (#4192) (sexy pig <<353071655@qq.com>>) - * [[`5e2bad0c4`](http://github.com/eggjs/egg/commit/5e2bad0c421952b7c84471df06d2ca80c20fa14c)] - docs: fix typo in router (#4203) (Xuemuyang <>) - * [[`1181a675c`](http://github.com/eggjs/egg/commit/1181a675cae08c2d6952b8c15a3a9375947e220b)] - docs(plugin): format en/basics/plugin.md (#4168) (chs97 <<623528324@qq.com>>) - * [[`e9011e8f3`](http://github.com/eggjs/egg/commit/e9011e8f332a97da7e6e112d0f1ded42f0b5db42)] - feat: add http method patch to typings (#4125) (xiaoxu <>) - * [[`2109505b4`](http://github.com/eggjs/egg/commit/2109505b40a159cd047075e566e9465b1ad5a365)] - test: fix doctools path on windows (#4090) (fengmk2 <>) - +- [[`9c67298d6`](http://github.com/eggjs/egg/commit/9c67298d69946d4ba0887c3648d3404e835c6902)] - test: run test on node 14 (#4272) (fengmk2 <>) +- [[`427a30a07`](http://github.com/eggjs/egg/commit/427a30a071d248cc2e5e15bb4bad35f3058e867f)] - test: make dnscache test case more stable (#4297) (Yiyu He <>) +- [[`64efd076b`](http://github.com/eggjs/egg/commit/64efd076bf9d937e36748f89bada6fce186913cd)] - fix: runInBackground always run after setImmediate (#4296) (Yiyu He <>) +- [[`69923977a`](http://github.com/eggjs/egg/commit/69923977a7e5c0825f2fc5c616852b0721411a0c)] - docs: Update doc for config of logger.consoleLevel (#4276) (xuxu <>) +- [[`7b6e4371c`](http://github.com/eggjs/egg/commit/7b6e4371c7367583627977a0ca4aa2ff66e28429)] - docs(typescript): Add --noEmit to unittest example code (#4250) (Ink <>) +- [[`3413e35fd`](http://github.com/eggjs/egg/commit/3413e35fd86408896e5c0b7e77ec2528ac08c9f9)] - chore: fix typo (#4234) (zoomdong <<1344492820@qq.com>>) +- [[`b4b9b50af`](http://github.com/eggjs/egg/commit/b4b9b50af1bb842e0138fc236d45882188698123)] - doc (socketio): fix packet middleware bug (#4204) (zfx <<502545703@qq.com>>) +- [[`2fcd605c6`](http://github.com/eggjs/egg/commit/2fcd605c6397480b0a5add9c11f7c7d071393de5)] - docs: update bodyParser types and doc (#4192) (sexy pig <<353071655@qq.com>>) +- [[`5e2bad0c4`](http://github.com/eggjs/egg/commit/5e2bad0c421952b7c84471df06d2ca80c20fa14c)] - docs: fix typo in router (#4203) (Xuemuyang <>) +- [[`1181a675c`](http://github.com/eggjs/egg/commit/1181a675cae08c2d6952b8c15a3a9375947e220b)] - docs(plugin): format en/basics/plugin.md (#4168) (chs97 <<623528324@qq.com>>) +- [[`e9011e8f3`](http://github.com/eggjs/egg/commit/e9011e8f332a97da7e6e112d0f1ded42f0b5db42)] - feat: add http method patch to typings (#4125) (xiaoxu <>) +- [[`2109505b4`](http://github.com/eggjs/egg/commit/2109505b40a159cd047075e566e9465b1ad5a365)] - test: fix doctools path on windows (#4090) (fengmk2 <>) ## 2019-12-07, Version 2.26.0 @fengmk2 ### Notable changes -* **features** - * add application level Cookie options, can fix [Cookie SameSite warning on Chrome](https://support.google.com/chrome/thread/16654793?hl=en) now. - * use new URL instead of url.parse, avoiding potential security issues. +- **features** + - add application level Cookie options, can fix [Cookie SameSite warning on Chrome](https://support.google.com/chrome/thread/16654793?hl=en) now. + - use new URL instead of url.parse, avoiding potential security issues. ### Commits - * [[`b28134e77`](http://github.com/eggjs/egg/commit/b28134e7709c803eb7a7ed071a25bac8a28e3d1f)] - feat: add application level Cookie options (#4086) (fengmk2 <>) - * [[`b7718c1cc`](http://github.com/eggjs/egg/commit/b7718c1cc2b94b02ee728088060fdbc85e462b6d)] - fix: use new URL instead of url.parse (#4048) (Yiyu He <>) - * [[`afed9105d`](http://github.com/eggjs/egg/commit/afed9105df34aad60c40ecba0e44ddaad1a605dc)] - fix: index.d.ts (#4012) (dxd <>) - * [[`690711bab`](http://github.com/eggjs/egg/commit/690711bab8bd8c838b4dd651baea3bc49a5fa1f1)] - test: fix the testcase error of load_boot.test.js (#4041) (Xin Wang <>) - * [[`6c55a436b`](http://github.com/eggjs/egg/commit/6c55a436bf2afb7bb99810401a6f92b3a58471ff)] - docs: fix typo (#4028) (Xuehua Cai <>) +- [[`b28134e77`](http://github.com/eggjs/egg/commit/b28134e7709c803eb7a7ed071a25bac8a28e3d1f)] - feat: add application level Cookie options (#4086) (fengmk2 <>) +- [[`b7718c1cc`](http://github.com/eggjs/egg/commit/b7718c1cc2b94b02ee728088060fdbc85e462b6d)] - fix: use new URL instead of url.parse (#4048) (Yiyu He <>) +- [[`afed9105d`](http://github.com/eggjs/egg/commit/afed9105df34aad60c40ecba0e44ddaad1a605dc)] - fix: index.d.ts (#4012) (dxd <>) +- [[`690711bab`](http://github.com/eggjs/egg/commit/690711bab8bd8c838b4dd651baea3bc49a5fa1f1)] - test: fix the testcase error of load_boot.test.js (#4041) (Xin Wang <>) +- [[`6c55a436b`](http://github.com/eggjs/egg/commit/6c55a436bf2afb7bb99810401a6f92b3a58471ff)] - docs: fix typo (#4028) (Xuehua Cai <>) ## 2019-10-28, Version 2.25.0 @dead-horse ### Notable changes -* **features** - * support config.maxIpsCount, deprecate config.maxProxyCount - * singleton returns client name when create client +- **features** + - support config.maxIpsCount, deprecate config.maxProxyCount + - singleton returns client name when create client ### Commits - * [[`b3479e8e2`](http://github.com/eggjs/egg/commit/b3479e8e2b6cc74c95eef4334bd6b054fddb6158)] - feat: support config.maxIpsCount (#4014) (Yiyu He <>) - * [[`380e7d634`](http://github.com/eggjs/egg/commit/380e7d6344b4f608397fed5dea4f19918ca347f5)] - docs(env): cleanup the document (#3988) (Alpha <>) - * [[`2c5e64a50`](http://github.com/eggjs/egg/commit/2c5e64a50edd78522aa5bf83e4ea8ef4d72f5b40)] - docs: add promo link (#3995) (Haoliang Gao <>) - * [[`adca16637`](http://github.com/eggjs/egg/commit/adca1663712acd361dddd1b390ca48dda5a3608e)] - docs(deployment): update the description for hostname (#3994) (Suyi <>) - * [[`27dacb7c9`](http://github.com/eggjs/egg/commit/27dacb7c9dae4b65c1b973d39aae1f8c9a4cd7b1)] - feat:Singleton returns client name when create client (#3905) (暗色调 <<41288382+dark-tone@users.noreply.github.com>>) - * [[`d3f68c371`](http://github.com/eggjs/egg/commit/d3f68c3710946a63f640b1885e9c7120db935d8e)] - docs(deployment): modify hostname (#3987) (zfx <<502545703@qq.com>>) - * [[`73ad6c086`](http://github.com/eggjs/egg/commit/73ad6c0861d5d6f8235fde2a5ba985ad9f53fcfe)] - chore: use github actions to run CI (#3974) (Suyi <>) - +- [[`b3479e8e2`](http://github.com/eggjs/egg/commit/b3479e8e2b6cc74c95eef4334bd6b054fddb6158)] - feat: support config.maxIpsCount (#4014) (Yiyu He <>) +- [[`380e7d634`](http://github.com/eggjs/egg/commit/380e7d6344b4f608397fed5dea4f19918ca347f5)] - docs(env): cleanup the document (#3988) (Alpha <>) +- [[`2c5e64a50`](http://github.com/eggjs/egg/commit/2c5e64a50edd78522aa5bf83e4ea8ef4d72f5b40)] - docs: add promo link (#3995) (Haoliang Gao <>) +- [[`adca16637`](http://github.com/eggjs/egg/commit/adca1663712acd361dddd1b390ca48dda5a3608e)] - docs(deployment): update the description for hostname (#3994) (Suyi <>) +- [[`27dacb7c9`](http://github.com/eggjs/egg/commit/27dacb7c9dae4b65c1b973d39aae1f8c9a4cd7b1)] - feat:Singleton returns client name when create client (#3905) (暗色调 <<41288382+dark-tone@users.noreply.github.com>>) +- [[`d3f68c371`](http://github.com/eggjs/egg/commit/d3f68c3710946a63f640b1885e9c7120db935d8e)] - docs(deployment): modify hostname (#3987) (zfx <<502545703@qq.com>>) +- [[`73ad6c086`](http://github.com/eggjs/egg/commit/73ad6c0861d5d6f8235fde2a5ba985ad9f53fcfe)] - chore: use github actions to run CI (#3974) (Suyi <>) ## 2019-10-11, Version 2.24.0 @thonatos ### Notable changes -* **features** - * feat: set default body-parser limitation to 1mb - -* **fixes** - * app.keys getter must have a setter either - * more log for bodyParser - -* **docs** - * add opencollective to sponsors list - * update lf url - * fix hsts docs error - * fix typo of socket.io - * modify invalid links - -### Commits - - * [[`bddf1e183`](http://github.com/eggjs/egg/commit/bddf1e183b5b6fc0f1414f81948ffdedd71e16a9)] - feat: set default body-parser limitation to 1mb (#3903) (Suyi <>) - * [[`5ddf07c43`](http://github.com/eggjs/egg/commit/5ddf07c435ad81142a6e995583849e20c7348dda)] - docs: update readme (#3968) (Suyi <>) - * [[`be1b72606`](http://github.com/eggjs/egg/commit/be1b72606a62a8efe88849976126cc8ca61b8d7e)] - docs(security): hsts is disabled by default (#3972) (Suyi <>) - * [[`e5e948783`](http://github.com/eggjs/egg/commit/e5e948783a45ea138592a33e9ae7faa20a85af26)] - docs: add opencollective to sponsors list (#3971) (Suyi <>) - * [[`cde921456`](http://github.com/eggjs/egg/commit/cde921456657c16dba81c6fb9c991b62a826d120)] - docs: update lf url (#3922) (Suyi <>) - * [[`17b22c86b`](http://github.com/eggjs/egg/commit/17b22c86b7f83bc168d9c7176191618e19add1dd)] - docs: fix typo of socket.io (#3895) (lqzhgood <<9134671+lqzhgood@users.noreply.github.com>>) - * [[`a9d0cf5c0`](http://github.com/eggjs/egg/commit/a9d0cf5c0d5aadc957e12854f7a3ab6469f83f75)] - fix: app.keys getter must have a setter either (#3891) (Yiyu He <>) - * [[`f1707410b`](http://github.com/eggjs/egg/commit/f1707410bc3f703d69aae27965cc622b9a768107)] - docs(deployment): add logs that the egg app has been successfully connected to alinode (#3868) (hyj1991 <>) - * [[`24c388b4a`](http://github.com/eggjs/egg/commit/24c388b4a5ec4c717875a1510accbd5882800ad0)] - docs(egg-and-koa): modify invalid links (#3851) (sdjdd <<352207572@qq.com>>) - * [[`84894e871`](http://github.com/eggjs/egg/commit/84894e8714747876821447faeaada0dabc2a7147)] - chore: add sponsor config (#3751) (TZ | 天猪 <>) - * [[`064616934`](http://github.com/eggjs/egg/commit/064616934b4ff2c044395baae60bd33d3d7dc5ff)] - chore: add node12 for ci (#3196) (Haoliang Gao <>) - * [[`45a966621`](http://github.com/eggjs/egg/commit/45a966621746f9d2c9e8a91fc1b17f75d97033de)] - docs(quickstart): npm version for npm init command (#3836) (QingDeng <>) - * [[`341beda59`](http://github.com/eggjs/egg/commit/341beda59ee99867998e28603f9ed623e49c33aa)] - test: mv assert to fixtures (#3829) (Suyi <>) - * [[`79dbb14a5`](http://github.com/eggjs/egg/commit/79dbb14a535c27a55daf83b441b47aabff472b06)] - docs(logger): formatter (#3835) (TZ | 天猪 <>) +- **features** + - feat: set default body-parser limitation to 1mb + +- **fixes** + - app.keys getter must have a setter either + - more log for bodyParser + +- **docs** + - add opencollective to sponsors list + - update lf url + - fix hsts docs error + - fix typo of socket.io + - modify invalid links + +### Commits + +- [[`bddf1e183`](http://github.com/eggjs/egg/commit/bddf1e183b5b6fc0f1414f81948ffdedd71e16a9)] - feat: set default body-parser limitation to 1mb (#3903) (Suyi <>) +- [[`5ddf07c43`](http://github.com/eggjs/egg/commit/5ddf07c435ad81142a6e995583849e20c7348dda)] - docs: update readme (#3968) (Suyi <>) +- [[`be1b72606`](http://github.com/eggjs/egg/commit/be1b72606a62a8efe88849976126cc8ca61b8d7e)] - docs(security): hsts is disabled by default (#3972) (Suyi <>) +- [[`e5e948783`](http://github.com/eggjs/egg/commit/e5e948783a45ea138592a33e9ae7faa20a85af26)] - docs: add opencollective to sponsors list (#3971) (Suyi <>) +- [[`cde921456`](http://github.com/eggjs/egg/commit/cde921456657c16dba81c6fb9c991b62a826d120)] - docs: update lf url (#3922) (Suyi <>) +- [[`17b22c86b`](http://github.com/eggjs/egg/commit/17b22c86b7f83bc168d9c7176191618e19add1dd)] - docs: fix typo of socket.io (#3895) (lqzhgood <<9134671+lqzhgood@users.noreply.github.com>>) +- [[`a9d0cf5c0`](http://github.com/eggjs/egg/commit/a9d0cf5c0d5aadc957e12854f7a3ab6469f83f75)] - fix: app.keys getter must have a setter either (#3891) (Yiyu He <>) +- [[`f1707410b`](http://github.com/eggjs/egg/commit/f1707410bc3f703d69aae27965cc622b9a768107)] - docs(deployment): add logs that the egg app has been successfully connected to alinode (#3868) (hyj1991 <>) +- [[`24c388b4a`](http://github.com/eggjs/egg/commit/24c388b4a5ec4c717875a1510accbd5882800ad0)] - docs(egg-and-koa): modify invalid links (#3851) (sdjdd <<352207572@qq.com>>) +- [[`84894e871`](http://github.com/eggjs/egg/commit/84894e8714747876821447faeaada0dabc2a7147)] - chore: add sponsor config (#3751) (TZ | 天猪 <>) +- [[`064616934`](http://github.com/eggjs/egg/commit/064616934b4ff2c044395baae60bd33d3d7dc5ff)] - chore: add node12 for ci (#3196) (Haoliang Gao <>) +- [[`45a966621`](http://github.com/eggjs/egg/commit/45a966621746f9d2c9e8a91fc1b17f75d97033de)] - docs(quickstart): npm version for npm init command (#3836) (QingDeng <>) +- [[`341beda59`](http://github.com/eggjs/egg/commit/341beda59ee99867998e28603f9ed623e49c33aa)] - test: mv assert to fixtures (#3829) (Suyi <>) +- [[`79dbb14a5`](http://github.com/eggjs/egg/commit/79dbb14a535c27a55daf83b441b47aabff472b06)] - docs(logger): formatter (#3835) (TZ | 天猪 <>) ## 2019-07-17, Version 2.23.0 @atian25 ### Notable changes -* **features** - * error message rewrite when it has only a getter - -* **fixes** - * handleRequest method should return a promise - * more log for bodyParser - -* **docs** - * httpclient upload files - * typings improve - -### Commits - - * [[`6bfc0eb5b`](http://github.com/eggjs/egg/commit/6bfc0eb5b9a6d38c73d46bf641ece6adda3481a1)] - feat: error message rewrite when it has only a getter (#3796) (TZ | 天猪 <>) - * [[`489f52b5c`](http://github.com/eggjs/egg/commit/489f52b5ce4078efccefc8837729b42c15828722)] - fix: handleRequest method should return a promise (#3820) (引证 <>) - * [[`29a2f2fd9`](http://github.com/eggjs/egg/commit/29a2f2fd92e4d3e3cf0ee9ff034d8cdce07ee693)] - fix: more log for bodyParser (#3809) (TZ | 天猪 <>) - * [[`6dc8a2d14`](http://github.com/eggjs/egg/commit/6dc8a2d14582c774479593f002af2f2b96e0ce96)] - chore: fix ci (#3825) (Suyi <>) - * [[`e30511eff`](http://github.com/eggjs/egg/commit/e30511effeb77d954e2c15b684c274b85da2c69b)] - docs: add alinode supported platforms (#3821) (hyj1991 <>) - * [[`c67ca2059`](http://github.com/eggjs/egg/commit/c67ca2059f2c44140e3a5bc46c38c87f52a08172)] - docs: open should come with protocol (#3787) (zhennann <>) - * [[`9adcd40f8`](http://github.com/eggjs/egg/commit/9adcd40f81a22670abf2f5f9167d9c8de438ad34)] - docs(lifecyle): add class export in sample code (#3758) (Kermit Xuan <<33770367+Kermit-Xuan@users.noreply.github.com>>) - * [[`4ca62734d`](http://github.com/eggjs/egg/commit/4ca62734db829cad7e3ea35bc6394de98c9ad160)] - fix: typos (#3768) (Jeff <>) - * [[`b1cb5332d`](http://github.com/eggjs/egg/commit/b1cb5332d433c158f59ab4877f3f6ab07bf9fe79)] - chore: remove @types/urllib (#3732) (TZ | 天猪 <>) - * [[`3de31f541`](http://github.com/eggjs/egg/commit/3de31f5418503f02afde9e92409d5f40e664c46c)] - fix(typings): add custom logger typings (#3697) (吖猩 <>) - * [[`35af6331c`](http://github.com/eggjs/egg/commit/35af6331c97b2e9c9f831ff193709f8fc984f3a9)] - docs: https options en version (#3702) (liulun <>) - * [[`9c23232a4`](http://github.com/eggjs/egg/commit/9c23232a47679bdcb8f071a5cc01f013f443aa05)] - docs(sequelize): replace findById with findByPk (#3700) (Zhao zuoqi <<30346283+Mavericker-1996@users.noreply.github.com>>) - * [[`3fccb4f27`](http://github.com/eggjs/egg/commit/3fccb4f275b2982b974a1a1d99cec32795f4efd3)] - docs: https options (#3701) (liulun <>) - * [[`5b2dbd5b0`](http://github.com/eggjs/egg/commit/5b2dbd5b097d80b0f9150d1a03ec1d9c73af8dec)] - test: fix some test methods failed on windows platform (#3686) (QingDeng <>) - * [[`409990299`](http://github.com/eggjs/egg/commit/409990299fd3afeb35968bc06b02f4b0137718ba)] - fix:add the doc test on windows (#3654) (Maledong <>) - * [[`17fab1c1d`](http://github.com/eggjs/egg/commit/17fab1c1d645076bda76be351fcb3c6f86cea4ca)] - docs: httpclient upload files (#3682) (TZ | 天猪 <>) - * [[`da2d439d6`](http://github.com/eggjs/egg/commit/da2d439d6f79f767055021bf96f7ef73207a751a)] - docs(lifecyle): fix typo (#3681) (+v <>) +- **features** + - error message rewrite when it has only a getter + +- **fixes** + - handleRequest method should return a promise + - more log for bodyParser + +- **docs** + - httpclient upload files + - typings improve + +### Commits + +- [[`6bfc0eb5b`](http://github.com/eggjs/egg/commit/6bfc0eb5b9a6d38c73d46bf641ece6adda3481a1)] - feat: error message rewrite when it has only a getter (#3796) (TZ | 天猪 <>) +- [[`489f52b5c`](http://github.com/eggjs/egg/commit/489f52b5ce4078efccefc8837729b42c15828722)] - fix: handleRequest method should return a promise (#3820) (引证 <>) +- [[`29a2f2fd9`](http://github.com/eggjs/egg/commit/29a2f2fd92e4d3e3cf0ee9ff034d8cdce07ee693)] - fix: more log for bodyParser (#3809) (TZ | 天猪 <>) +- [[`6dc8a2d14`](http://github.com/eggjs/egg/commit/6dc8a2d14582c774479593f002af2f2b96e0ce96)] - chore: fix ci (#3825) (Suyi <>) +- [[`e30511eff`](http://github.com/eggjs/egg/commit/e30511effeb77d954e2c15b684c274b85da2c69b)] - docs: add alinode supported platforms (#3821) (hyj1991 <>) +- [[`c67ca2059`](http://github.com/eggjs/egg/commit/c67ca2059f2c44140e3a5bc46c38c87f52a08172)] - docs: open should come with protocol (#3787) (zhennann <>) +- [[`9adcd40f8`](http://github.com/eggjs/egg/commit/9adcd40f81a22670abf2f5f9167d9c8de438ad34)] - docs(lifecyle): add class export in sample code (#3758) (Kermit Xuan <<33770367+Kermit-Xuan@users.noreply.github.com>>) +- [[`4ca62734d`](http://github.com/eggjs/egg/commit/4ca62734db829cad7e3ea35bc6394de98c9ad160)] - fix: typos (#3768) (Jeff <>) +- [[`b1cb5332d`](http://github.com/eggjs/egg/commit/b1cb5332d433c158f59ab4877f3f6ab07bf9fe79)] - chore: remove @types/urllib (#3732) (TZ | 天猪 <>) +- [[`3de31f541`](http://github.com/eggjs/egg/commit/3de31f5418503f02afde9e92409d5f40e664c46c)] - fix(typings): add custom logger typings (#3697) (吖猩 <>) +- [[`35af6331c`](http://github.com/eggjs/egg/commit/35af6331c97b2e9c9f831ff193709f8fc984f3a9)] - docs: https options en version (#3702) (liulun <>) +- [[`9c23232a4`](http://github.com/eggjs/egg/commit/9c23232a47679bdcb8f071a5cc01f013f443aa05)] - docs(sequelize): replace findById with findByPk (#3700) (Zhao zuoqi <<30346283+Mavericker-1996@users.noreply.github.com>>) +- [[`3fccb4f27`](http://github.com/eggjs/egg/commit/3fccb4f275b2982b974a1a1d99cec32795f4efd3)] - docs: https options (#3701) (liulun <>) +- [[`5b2dbd5b0`](http://github.com/eggjs/egg/commit/5b2dbd5b097d80b0f9150d1a03ec1d9c73af8dec)] - test: fix some test methods failed on windows platform (#3686) (QingDeng <>) +- [[`409990299`](http://github.com/eggjs/egg/commit/409990299fd3afeb35968bc06b02f4b0137718ba)] - fix:add the doc test on windows (#3654) (Maledong <>) +- [[`17fab1c1d`](http://github.com/eggjs/egg/commit/17fab1c1d645076bda76be351fcb3c6f86cea4ca)] - docs: httpclient upload files (#3682) (TZ | 天猪 <>) +- [[`da2d439d6`](http://github.com/eggjs/egg/commit/da2d439d6f79f767055021bf96f7ef73207a751a)] - docs(lifecyle): fix typo (#3681) (+v <>) ## 2019-04-30, Version 2.22.2 @atian25 ### Notable changes -* **fixes** - * optimize declaration of httpclient +- **fixes** + - optimize declaration of httpclient ### Commits - * [[`670ba3475`](http://github.com/eggjs/egg/commit/670ba34751af0b3869dd656064b4587affb888ec)] - fix(typings): optimize declaration of httpclient (#3665) (吖猩 <>) +- [[`670ba3475`](http://github.com/eggjs/egg/commit/670ba34751af0b3869dd656064b4587affb888ec)] - fix(typings): optimize declaration of httpclient (#3665) (吖猩 <>) ## 2019-04-29, Version 2.22.1 @atian25 ### Notable changes -* **fixes** - * should restore agent messenger first +- **fixes** + - should restore agent messenger first ### Commits - * [[`04adcf93b`](http://github.com/eggjs/egg/commit/04adcf93b8f0a8c48c35015e8d2a279fc7d06b24)] - fix: should restore agent messenger first (#3658) (TZ | 天猪 <>) - * [[`99eb75398`](http://github.com/eggjs/egg/commit/99eb7539850c117d3d8b05f669cae5a9e9269be8)] - docs: fix history time (#3655) (TZ | 天猪 <>) +- [[`04adcf93b`](http://github.com/eggjs/egg/commit/04adcf93b8f0a8c48c35015e8d2a279fc7d06b24)] - fix: should restore agent messenger first (#3658) (TZ | 天猪 <>) +- [[`99eb75398`](http://github.com/eggjs/egg/commit/99eb7539850c117d3d8b05f669cae5a9e9269be8)] - docs: fix history time (#3655) (TZ | 天猪 <>) ## 2019-04-29, Version 2.22.0 @atian25 ### Notable changes -* **features** - * switch httpclient to httpclient2 for retry feature - * add BaseHookClass +- **features** + - switch httpclient to httpclient2 for retry feature + - add BaseHookClass -* **fixes** - * loadCustomLoader should be run before loadCustomApp +- **fixes** + - loadCustomLoader should be run before loadCustomApp -* **docs** - * d.ts for single mode +- **docs** + - d.ts for single mode ### Commits - * [[`d3b1cb5d9`](http://github.com/eggjs/egg/commit/d3b1cb5d9d2dd91330778966ba9813f56476a47b)] - fix: loadCustomLoader should be run before loadCustomApp (#3652) (Haoliang Gao <>) - * [[`7cc8aab02`](http://github.com/eggjs/egg/commit/7cc8aab02d89869b4ce460b2fa186aedcf00b64b)] - chore: update packages,remove 'plugin' and validations of doc generation (#3643) (Maledong <>) - * [[`bffb6448f`](http://github.com/eggjs/egg/commit/bffb6448f201ce0d61bd3a32b91f673cf5c074f4)] - docs: fix httpclient proxy (#3638) (TZ | 天猪 <>) - * [[`e7fbd68f3`](http://github.com/eggjs/egg/commit/e7fbd68f32054041b74bc860f11aca05c025c0a9)] - feat: switch httpclient to httpclient2 for retry feature (#3626) (TZ | 天猪 <>) - * [[`8bb7c7e7d`](http://github.com/eggjs/egg/commit/8bb7c7e7d59d6aeca4b2ed1eb580368dcb731a4d)] - feat: add BaseHookClass (#3581) (killa <>) - * [[`459454354`](http://github.com/eggjs/egg/commit/4594543543290a8c714fe3b9047c84578bf2f9a6)] - feat: index.d.ts添加单进程模式 (#3628) (jasine <>) - * [[`4b13a1ffb`](http://github.com/eggjs/egg/commit/4b13a1ffbed0895731bf38f72d5786d4b15f263f)] - chore: fix jsdocs (#3627) (TZ | 天猪 <>) +- [[`d3b1cb5d9`](http://github.com/eggjs/egg/commit/d3b1cb5d9d2dd91330778966ba9813f56476a47b)] - fix: loadCustomLoader should be run before loadCustomApp (#3652) (Haoliang Gao <>) +- [[`7cc8aab02`](http://github.com/eggjs/egg/commit/7cc8aab02d89869b4ce460b2fa186aedcf00b64b)] - chore: update packages,remove 'plugin' and validations of doc generation (#3643) (Maledong <>) +- [[`bffb6448f`](http://github.com/eggjs/egg/commit/bffb6448f201ce0d61bd3a32b91f673cf5c074f4)] - docs: fix httpclient proxy (#3638) (TZ | 天猪 <>) +- [[`e7fbd68f3`](http://github.com/eggjs/egg/commit/e7fbd68f32054041b74bc860f11aca05c025c0a9)] - feat: switch httpclient to httpclient2 for retry feature (#3626) (TZ | 天猪 <>) +- [[`8bb7c7e7d`](http://github.com/eggjs/egg/commit/8bb7c7e7d59d6aeca4b2ed1eb580368dcb731a4d)] - feat: add BaseHookClass (#3581) (killa <>) +- [[`459454354`](http://github.com/eggjs/egg/commit/4594543543290a8c714fe3b9047c84578bf2f9a6)] - feat: index.d.ts添加单进程模式 (#3628) (jasine <>) +- [[`4b13a1ffb`](http://github.com/eggjs/egg/commit/4b13a1ffbed0895731bf38f72d5786d4b15f263f)] - chore: fix jsdocs (#3627) (TZ | 天猪 <>) ## 2019-04-12, Version 2.21.1 @dead-horse ### Notable changes -* **fixes** - * Revert "feat: switch httpclient to httpclient2 for retry feature(which is a breaking change) +- **fixes** + - Revert "feat: switch httpclient to httpclient2 for retry feature(which is a breaking change) ### Commits - * [[`89872a76f`](http://github.com/eggjs/egg/commit/89872a76fc09cefb9ff92221a5c3b9977d206f7c)] - Revert "feat: switch httpclient to httpclient2 for retry feature (#36… (#3622) (Yiyu He <>) +- [[`89872a76f`](http://github.com/eggjs/egg/commit/89872a76fc09cefb9ff92221a5c3b9977d206f7c)] - Revert "feat: switch httpclient to httpclient2 for retry feature (#36… (#3622) (Yiyu He <>) ## 2019-04-11, Version 2.21.0 @dead-horse ### Notable changes -* **features** - * support config.maxProxyCount to help get the real client ip - * switch httpclient to httpclient2 for retry feature +- **features** + - support config.maxProxyCount to help get the real client ip + - switch httpclient to httpclient2 for retry feature -* **docs** - * add how to config egg behind a proxy - * update http_proxy usage - * change `egg-init` to `npm init egg` +- **docs** + - add how to config egg behind a proxy + - update http_proxy usage + - change `egg-init` to `npm init egg` ### Commits - * [[`01b9588a3`](http://github.com/eggjs/egg/commit/01b9588a35ba33a7088e79f6d3e08c713c4de963)] - feat: support config.maxProxyCount to help get the real client ip (#3612) (Yiyu He <>) - * [[`eead31862`](http://github.com/eggjs/egg/commit/eead318625347bb9de8f9d7ffc6fae5ae1b33901)] - feat: switch httpclient to httpclient2 for retry feature (#3606) (TZ | 天猪 <>) - * [[`879fe93a6`](http://github.com/eggjs/egg/commit/879fe93a6dde156101318c766a3c29ca07f1e18d)] - docs: add how to config egg behind a proxy (#3614) (Yiyu He <>) - * [[`2357fbc1e`](http://github.com/eggjs/egg/commit/2357fbc1ee18cf0a8ee8692ed2d62d2224acfe3b)] - docs: remove egg-ts-helper && inspect-brk (#3603) (TZ | 天猪 <>) - * [[`e0a1d8fc6`](http://github.com/eggjs/egg/commit/e0a1d8fc6806acc0a4141bc4cf67149069bfbdf0)] - docs: change egg-init to `npm init egg` (#3588) (TZ | 天猪 <>) - * [[`763923cd7`](http://github.com/eggjs/egg/commit/763923cd76be30496fee9f733db9500c1d8188f2)] - chore: remove unused plugins.puml link (#3579) (TZ | 天猪 <>) - * [[`b1746468d`](http://github.com/eggjs/egg/commit/b1746468dae2d02aeef37f6e8d85414624c79880)] - docs(httpclient): update http_proxy usage (#3569) (TZ | 天猪 <>) - +- [[`01b9588a3`](http://github.com/eggjs/egg/commit/01b9588a35ba33a7088e79f6d3e08c713c4de963)] - feat: support config.maxProxyCount to help get the real client ip (#3612) (Yiyu He <>) +- [[`eead31862`](http://github.com/eggjs/egg/commit/eead318625347bb9de8f9d7ffc6fae5ae1b33901)] - feat: switch httpclient to httpclient2 for retry feature (#3606) (TZ | 天猪 <>) +- [[`879fe93a6`](http://github.com/eggjs/egg/commit/879fe93a6dde156101318c766a3c29ca07f1e18d)] - docs: add how to config egg behind a proxy (#3614) (Yiyu He <>) +- [[`2357fbc1e`](http://github.com/eggjs/egg/commit/2357fbc1ee18cf0a8ee8692ed2d62d2224acfe3b)] - docs: remove egg-ts-helper && inspect-brk (#3603) (TZ | 天猪 <>) +- [[`e0a1d8fc6`](http://github.com/eggjs/egg/commit/e0a1d8fc6806acc0a4141bc4cf67149069bfbdf0)] - docs: change egg-init to `npm init egg` (#3588) (TZ | 天猪 <>) +- [[`763923cd7`](http://github.com/eggjs/egg/commit/763923cd76be30496fee9f733db9500c1d8188f2)] - chore: remove unused plugins.puml link (#3579) (TZ | 天猪 <>) +- [[`b1746468d`](http://github.com/eggjs/egg/commit/b1746468dae2d02aeef37f6e8d85414624c79880)] - docs(httpclient): update http_proxy usage (#3569) (TZ | 天猪 <>) ## 2019-03-25, Version 2.20.2 @whxaxes ### Notable changes -* **fixes** - * onClientError remove content-length header +- **fixes** + - onClientError remove content-length header -* **types** - * add custom loader typing - * import types from egg-core +- **types** + - add custom loader typing + - import types from egg-core ### Commits - * [[`f31cd38aa`](http://github.com/eggjs/egg/commit/f31cd38aa1c1cb58f4fb6b08020b0b49a9b5c1a8)] - fix(types): add custom loader typing (#3533) (吖猩 <>) - * [[`a73cfd067`](http://github.com/eggjs/egg/commit/a73cfd067b48b2c2301e50d5ab431dfecebddef4)] - fix(types): import types from egg-core (#3545) (吖猩 <>) - * [[`04adb930d`](http://github.com/eggjs/egg/commit/04adb930de61f6c3d1b7b9b4e7f49800e3b49602)] - fix: onClientError remove content-length header (#3544) (Yiyu He <>) +- [[`f31cd38aa`](http://github.com/eggjs/egg/commit/f31cd38aa1c1cb58f4fb6b08020b0b49a9b5c1a8)] - fix(types): add custom loader typing (#3533) (吖猩 <>) +- [[`a73cfd067`](http://github.com/eggjs/egg/commit/a73cfd067b48b2c2301e50d5ab431dfecebddef4)] - fix(types): import types from egg-core (#3545) (吖猩 <>) +- [[`04adb930d`](http://github.com/eggjs/egg/commit/04adb930de61f6c3d1b7b9b4e7f49800e3b49602)] - fix: onClientError remove content-length header (#3544) (Yiyu He <>) ## 2019-03-12, Version 2.20.1 @dead-horse ### Notable changes -* **fixes** - * empty querystring must be cached - * add Singleton class declare typings +- **fixes** + - empty querystring must be cached + - add Singleton class declare typings ### Commits - * [[`2fc241a86`](http://github.com/eggjs/egg/commit/2fc241a8648d64faab78196ccd0377c781287e5e)] - fix: add Singleton class declare typings (#3522) (mars <>) - * [[`981bad58b`](http://github.com/eggjs/egg/commit/981bad58ba6c4644b8bbbd818a43bf0dd62e206f)] - fix: empty querystring must be cached (#3535) (Yiyu He <>) - +- [[`2fc241a86`](http://github.com/eggjs/egg/commit/2fc241a8648d64faab78196ccd0377c781287e5e)] - fix: add Singleton class declare typings (#3522) (mars <>) +- [[`981bad58b`](http://github.com/eggjs/egg/commit/981bad58ba6c4644b8bbbd818a43bf0dd62e206f)] - fix: empty querystring must be cached (#3535) (Yiyu He <>) ## 2019-03-07, Version 2.20.0 @popomore ### Notable changes -* **features** - * support customLoader +- **features** + - support customLoader -* **chore** - * fix typo - * fix testcase +- **chore** + - fix typo + - fix testcase ### Commits - * [[`4cf06da27`](http://github.com/eggjs/egg/commit/4cf06da272a3f71b864efb6780ddfe2e6c1ad37c)] - feat: support customLoader (#3484) (Haoliang Gao <>) - * [[`2f2bd69bb`](http://github.com/eggjs/egg/commit/2f2bd69bb5a5ef5f9d45514c0640f3849bc64293)] - chore:Fix some typos in Chinese and English (#3514) (Maledong <>) - * [[`65bdd158c`](http://github.com/eggjs/egg/commit/65bdd158caf38abfc945de9aad8367a8567b1a18)] - Fix(cluster-client.test.js):Rollback to previous (#3507) (Maledong <>) +- [[`4cf06da27`](http://github.com/eggjs/egg/commit/4cf06da272a3f71b864efb6780ddfe2e6c1ad37c)] - feat: support customLoader (#3484) (Haoliang Gao <>) +- [[`2f2bd69bb`](http://github.com/eggjs/egg/commit/2f2bd69bb5a5ef5f9d45514c0640f3849bc64293)] - chore:Fix some typos in Chinese and English (#3514) (Maledong <>) +- [[`65bdd158c`](http://github.com/eggjs/egg/commit/65bdd158caf38abfc945de9aad8367a8567b1a18)] - Fix(cluster-client.test.js):Rollback to previous (#3507) (Maledong <>) ## 2019-02-28, Version 2.19.0 @dead-horse ### Notable changes -* **features** - * single mode support ignore warning +- **features** + - single mode support ignore warning -* **fixes** - * fix type defined +- **fixes** + - fix type defined ### Commits - * [[`18efac152`](http://github.com/eggjs/egg/commit/18efac152dd5cf789d1e79b1c1fb1fb4ec2013a1)] - feat: single mode support ignore warning (#3501) (Yiyu He <>) - * [[`f9eea2a4d`](http://github.com/eggjs/egg/commit/f9eea2a4da805a1b2f0e8883860266d68eb432ff)] - fix(types): getFileStream options types (#3500) (kayikay <<469797590@qq.com>>) +- [[`18efac152`](http://github.com/eggjs/egg/commit/18efac152dd5cf789d1e79b1c1fb1fb4ec2013a1)] - feat: single mode support ignore warning (#3501) (Yiyu He <>) +- [[`f9eea2a4d`](http://github.com/eggjs/egg/commit/f9eea2a4da805a1b2f0e8883860266d68eb432ff)] - fix(types): getFileStream options types (#3500) (kayikay <<469797590@qq.com>>) ## 2019-02-26, Version 2.18.0 @dead-horse ### Notable changes -* **features** - * cluster-client support single process mode +- **features** + - cluster-client support single process mode -* **fixes** - * fix type defined +- **fixes** + - fix type defined ### Commits - * [[`db1093128`](http://github.com/eggjs/egg/commit/db10931281dd39106e5c657e358117abd39b2103)] - feat: cluster-client support single cpu mode (#3497) (zōng yǔ <>) - * [[`f7e6ab535`](http://github.com/eggjs/egg/commit/f7e6ab535df378b35dfe6b6b49d7e009dc2bcf3f)] - doc (typescript.md): Chinese translation for the beginning of TypeScript's Introduction (#3488) (Maledong <>) - * [[`ac7e9a6b6`](http://github.com/eggjs/egg/commit/ac7e9a6b6d732d946dc238d9bad3eaabb81a1b70)] - fix: helper type (#3483) (吖猩 <>) - +- [[`db1093128`](http://github.com/eggjs/egg/commit/db10931281dd39106e5c657e358117abd39b2103)] - feat: cluster-client support single cpu mode (#3497) (zōng yǔ <>) +- [[`f7e6ab535`](http://github.com/eggjs/egg/commit/f7e6ab535df378b35dfe6b6b49d7e009dc2bcf3f)] - doc (typescript.md): Chinese translation for the beginning of TypeScript's Introduction (#3488) (Maledong <>) +- [[`ac7e9a6b6`](http://github.com/eggjs/egg/commit/ac7e9a6b6d732d946dc238d9bad3eaabb81a1b70)] - fix: helper type (#3483) (吖猩 <>) ## 2019-02-21, Version 2.17.0 @dead-horse ### Notable changes -* **features** - * agent context can be extended +- **features** + - agent context can be extended -* **fixes** - * createAnonymousContext add host in headers +- **fixes** + - createAnonymousContext add host in headers ### Commits -* [[`7147b23cf`](http://github.com/eggjs/egg/commit/7147b23cf7edaa98a8f009d98de7ef2aaa5303a0)] - feat: agent context can be extended (#3478) (Hongcai Deng <>) -* [[`a2f0d9620`](http://github.com/eggjs/egg/commit/a2f0d96204e05f11c5586ff0fa9441f4e3ab5dff)] - fix: createAnonymousContext add host in headers (#3477) (Yiyu He <>) -* [[`5952d1240`](http://github.com/eggjs/egg/commit/5952d12404ae896a2338ee4ee79d68876ffbb205)] - docs(typescript): fix wrong path of LifeCycle (#3475) (CHANG, TZU-YEN <>) + +- [[`7147b23cf`](http://github.com/eggjs/egg/commit/7147b23cf7edaa98a8f009d98de7ef2aaa5303a0)] - feat: agent context can be extended (#3478) (Hongcai Deng <>) +- [[`a2f0d9620`](http://github.com/eggjs/egg/commit/a2f0d96204e05f11c5586ff0fa9441f4e3ab5dff)] - fix: createAnonymousContext add host in headers (#3477) (Yiyu He <>) +- [[`5952d1240`](http://github.com/eggjs/egg/commit/5952d12404ae896a2338ee4ee79d68876ffbb205)] - docs(typescript): fix wrong path of LifeCycle (#3475) (CHANG, TZU-YEN <>) ## 2019-02-18, Version 2.16.2 @dead-horse ### Notable changes -* **fixes** - * fix: messenger in single process mode support send without `to` +- **fixes** + - fix: messenger in single process mode support send without `to` ### Commits - * [[`eac494184`](http://github.com/eggjs/egg/commit/eac4941846948ca6bb8a357d525ad82737425005)] - fix: support send without to argument (#3472) (Yiyu He <>) - +- [[`eac494184`](http://github.com/eggjs/egg/commit/eac4941846948ca6bb8a357d525ad82737425005)] - fix: support send without to argument (#3472) (Yiyu He <>) ## 2019-02-15, Version 2.16.1 @atian25 ### Notable changes -* **docs** - * remove declaration of view +- **docs** + - remove declaration of view -* **others** - * update dependencies +- **others** + - update dependencies ### Commits - * [[`1e859f2e2`](http://github.com/eggjs/egg/commit/1e859f2e200260cab95ac0b860d85609eb3eec06)] - feat(types): remove declaration of view (#3466) (吖猩 <>) - * [[`4a3ab5ac0`](http://github.com/eggjs/egg/commit/4a3ab5ac0324537fc3cdbcc0e84e3085b8a34586)] - deps: update dependencies (#3464) (Yiyu He <>) +- [[`1e859f2e2`](http://github.com/eggjs/egg/commit/1e859f2e200260cab95ac0b860d85609eb3eec06)] - feat(types): remove declaration of view (#3466) (吖猩 <>) +- [[`4a3ab5ac0`](http://github.com/eggjs/egg/commit/4a3ab5ac0324537fc3cdbcc0e84e3085b8a34586)] - deps: update dependencies (#3464) (Yiyu He <>) ## 2019-02-14, Version 2.16.0 @dead-horse ### Notable changes -* **features** - * allow ctx.router setter +- **features** + - allow ctx.router setter -* **others** - * more document improvement +- **others** + - more document improvement ### Commits - * [[`0b67c85f6`](http://github.com/eggjs/egg/commit/0b67c85f6f1798b2d3f377fb5ea336c96b60b6e3)] - feat: allow ctx.router setter (#3460) (fengmk2 <>) - * [[`ae5f56f3e`](http://github.com/eggjs/egg/commit/ae5f56f3e9b60eaa3507db44736020f3a13ec6f1)] - chore: Add principles for English titles and change all English titles (#3444) (Maledong <>) - * [[`a9bee07da`](http://github.com/eggjs/egg/commit/a9bee07daff1530da7350f9ad1ea56e21aa3eead)] - docs(sequelize): fix init doc (#3456) (Yiyu He <>) - * [[`f76c23052`](http://github.com/eggjs/egg/commit/f76c23052c86afcf158087f8b13a7e47ef76f67c)] - docs(logger): add logger.outputJSON to docs (#3425) (FX <>) - +- [[`0b67c85f6`](http://github.com/eggjs/egg/commit/0b67c85f6f1798b2d3f377fb5ea336c96b60b6e3)] - feat: allow ctx.router setter (#3460) (fengmk2 <>) +- [[`ae5f56f3e`](http://github.com/eggjs/egg/commit/ae5f56f3e9b60eaa3507db44736020f3a13ec6f1)] - chore: Add principles for English titles and change all English titles (#3444) (Maledong <>) +- [[`a9bee07da`](http://github.com/eggjs/egg/commit/a9bee07daff1530da7350f9ad1ea56e21aa3eead)] - docs(sequelize): fix init doc (#3456) (Yiyu He <>) +- [[`f76c23052`](http://github.com/eggjs/egg/commit/f76c23052c86afcf158087f8b13a7e47ef76f67c)] - docs(logger): add logger.outputJSON to docs (#3425) (FX <>) ## 2019-02-04, Version 2.15.1 @dead-horse ### Notable changes -* **fixes** - * add missing framework support for single process mode +- **fixes** + - add missing framework support for single process mode ### Commits - * [[`277c024cf`](http://github.com/eggjs/egg/commit/277c024cf565948547dbc7a518d39d7f55318f58)] - fix: add missing framework support for single process mode (#3445) (Yiyu He <>) +- [[`277c024cf`](http://github.com/eggjs/egg/commit/277c024cf565948547dbc7a518d39d7f55318f58)] - fix: add missing framework support for single process mode (#3445) (Yiyu He <>) ## 2019-02-03, Version 2.15.0 @dead-horse ### Notable changes -* **features** - * [EXPERIMENT FEATURE] support single process mode - -* **fixes** - * [TYPE] array supporting for config.static.dir - * [TYPE] fix IMiddleware type is incompatible - * [TYPE] fix type error while esModuleInterop is true - -* **others** - * more document improvement - -### Commits - - * [[`83c423a0a`](http://github.com/eggjs/egg/commit/83c423a0a985e701bfaef7f10372268b4ce8cef5)] - docs(development.md): Add English translation (Jennie <>) - * [[`d79da17bd`](http://github.com/eggjs/egg/commit/d79da17bdbe94f7b78d923caa10abf21e6c5f752)] - fix: type error while esModuleInterop is true (#3436) (吖猩 <>) - * [[`20ba4632b`](http://github.com/eggjs/egg/commit/20ba4632ba32e3b81e760678b4bbe00cdf05388e)] - feat: support single process mode (#3430) (Yiyu He <>) - * [[`133616961`](http://github.com/eggjs/egg/commit/133616961e5a2e95d5e2cd1254d7304c846b859c)] - docs: fix typo in socketio.md (#3431) (kilmas <>) - * [[`e899630e9`](http://github.com/eggjs/egg/commit/e899630e97865701b81d428686a19288b1c87b98)] - fix: array supporting for config.static.dir (#3421) (Gray <>) - * [[`43f2e3c44`](http://github.com/eggjs/egg/commit/43f2e3c449a7b448506d2484ed729618b06bffec)] - fix: IMiddleware type is incompatible (#3419) (吖猩 <>) - * [[`b3256b54e`](http://github.com/eggjs/egg/commit/b3256b54eeb09b2cee3cfdb75e98d6c090844a10)] - doc:Add new loaderUpdate.md (#3395) (Maledong <>) - * [[`71768002a`](http://github.com/eggjs/egg/commit/71768002a468a8fd30b9516c0bed85fa27b99b0a)] - docs: Wrong words are corrected (#3418) (巧克力冰激凌 <<121017405@qq.com>>) - * [[`20d56c7a8`](http://github.com/eggjs/egg/commit/20d56c7a83a74bb81ee47b0b8c2785db15519996)] - fix: fix ts ci (#3416) (吖猩 <>) - * [[`8beacd13e`](http://github.com/eggjs/egg/commit/8beacd13e3bcfff6b6a1e02eea72cafdd343858c)] - docs(logger): add logger.disableConsoleAfterReady to docs (#3384) (吖猩 <>) - * [[`271bc6372`](http://github.com/eggjs/egg/commit/271bc63722723531556bbec06d621f964ad1db33)] - chore: typo "submit an PR" should be "submit a PR" (#3408) (DAI JIE <>) - * [[`688f67c9f`](http://github.com/eggjs/egg/commit/688f67c9f329c71ea4469b9d28d5ee41815831ed)] - Chore: Fix some chore issues (#3400) (Maledong <>) - * [[`cfcebc623`](http://github.com/eggjs/egg/commit/cfcebc6234c62780c6aecf84db3862efd74e430c)] - doc (typescript.md): Sync the English translation (#3397) (Maledong <>) - * [[`7e5ef2181`](http://github.com/eggjs/egg/commit/7e5ef21811f98e5d55884f2574092e6f2e7b619b)] - docs(typescript): optimize docs of typescript (#3374) (吖猩 <>) - * [[`2a801f789`](http://github.com/eggjs/egg/commit/2a801f789f6e60427657b507951de8fc8e4a830f)] - chore: comments typo fix (#3392) (Jeff <>) - * [[`9a4b72062`](http://github.com/eggjs/egg/commit/9a4b7206212a27d37a37a1d68b4739be306b1a7a)] - chore: fix issue template (#3369) (Suyi <>) - * [[`ef73396a5`](http://github.com/eggjs/egg/commit/ef73396a5828c6b4e55c85cd2b27c3830bd306e5)] - docs: improve debug docs (#3370) (TZ | 天猪 <>) - * [[`874e57fda`](http://github.com/eggjs/egg/commit/874e57fda480d3295c1b1b30198ca3493f57814d)] - docs(sequelize): fix init (#3372) (Yiyu He <>) - * [[`b2152c56f`](http://github.com/eggjs/egg/commit/b2152c56f525a87fe0c1cfe66949005f308e1569)] - Chore: Fix some typo translations (#3361) (Maledong <>) - * [[`d275929d1`](http://github.com/eggjs/egg/commit/d275929d17830c95a2c828611b5ca54ffb747270)] - docs(boot): update app start document (#3348) (Yiyu He <>) - * [[`9a8652beb`](http://github.com/eggjs/egg/commit/9a8652bebc29f3d097039196b10daa2575f49695)] - Fix: Change the diagram of "starting process" (#3358) (Maledong <>) - * [[`ac0f13bc6`](http://github.com/eggjs/egg/commit/ac0f13bc604ebfc08185b336a106ec7e5d1bc98f)] - Chore: Add missing links for "Sails" and union the spellings of "Plugin" (#3356) (Maledong <>) - * [[`cd52b063b`](http://github.com/eggjs/egg/commit/cd52b063b60e15bc78c440fdebc00ddd3dca9909)] - docs(cluster-and-ipc.md): fix typos and formatting errors (#3357) (Darren Poon <>) - * [[`37e3c1aba`](http://github.com/eggjs/egg/commit/37e3c1abab31f47fc492574464657a57ff686b2b)] - Chroe: Fix something in articles (#3349) (Maledong <>) +- **features** + - [EXPERIMENT FEATURE] support single process mode + +- **fixes** + - [TYPE] array supporting for config.static.dir + - [TYPE] fix IMiddleware type is incompatible + - [TYPE] fix type error while esModuleInterop is true + +- **others** + - more document improvement + +### Commits + +- [[`83c423a0a`](http://github.com/eggjs/egg/commit/83c423a0a985e701bfaef7f10372268b4ce8cef5)] - docs(development.md): Add English translation (Jennie <>) +- [[`d79da17bd`](http://github.com/eggjs/egg/commit/d79da17bdbe94f7b78d923caa10abf21e6c5f752)] - fix: type error while esModuleInterop is true (#3436) (吖猩 <>) +- [[`20ba4632b`](http://github.com/eggjs/egg/commit/20ba4632ba32e3b81e760678b4bbe00cdf05388e)] - feat: support single process mode (#3430) (Yiyu He <>) +- [[`133616961`](http://github.com/eggjs/egg/commit/133616961e5a2e95d5e2cd1254d7304c846b859c)] - docs: fix typo in socketio.md (#3431) (kilmas <>) +- [[`e899630e9`](http://github.com/eggjs/egg/commit/e899630e97865701b81d428686a19288b1c87b98)] - fix: array supporting for config.static.dir (#3421) (Gray <>) +- [[`43f2e3c44`](http://github.com/eggjs/egg/commit/43f2e3c449a7b448506d2484ed729618b06bffec)] - fix: IMiddleware type is incompatible (#3419) (吖猩 <>) +- [[`b3256b54e`](http://github.com/eggjs/egg/commit/b3256b54eeb09b2cee3cfdb75e98d6c090844a10)] - doc:Add new loaderUpdate.md (#3395) (Maledong <>) +- [[`71768002a`](http://github.com/eggjs/egg/commit/71768002a468a8fd30b9516c0bed85fa27b99b0a)] - docs: Wrong words are corrected (#3418) (巧克力冰激凌 <<121017405@qq.com>>) +- [[`20d56c7a8`](http://github.com/eggjs/egg/commit/20d56c7a83a74bb81ee47b0b8c2785db15519996)] - fix: fix ts ci (#3416) (吖猩 <>) +- [[`8beacd13e`](http://github.com/eggjs/egg/commit/8beacd13e3bcfff6b6a1e02eea72cafdd343858c)] - docs(logger): add logger.disableConsoleAfterReady to docs (#3384) (吖猩 <>) +- [[`271bc6372`](http://github.com/eggjs/egg/commit/271bc63722723531556bbec06d621f964ad1db33)] - chore: typo "submit an PR" should be "submit a PR" (#3408) (DAI JIE <>) +- [[`688f67c9f`](http://github.com/eggjs/egg/commit/688f67c9f329c71ea4469b9d28d5ee41815831ed)] - Chore: Fix some chore issues (#3400) (Maledong <>) +- [[`cfcebc623`](http://github.com/eggjs/egg/commit/cfcebc6234c62780c6aecf84db3862efd74e430c)] - doc (typescript.md): Sync the English translation (#3397) (Maledong <>) +- [[`7e5ef2181`](http://github.com/eggjs/egg/commit/7e5ef21811f98e5d55884f2574092e6f2e7b619b)] - docs(typescript): optimize docs of typescript (#3374) (吖猩 <>) +- [[`2a801f789`](http://github.com/eggjs/egg/commit/2a801f789f6e60427657b507951de8fc8e4a830f)] - chore: comments typo fix (#3392) (Jeff <>) +- [[`9a4b72062`](http://github.com/eggjs/egg/commit/9a4b7206212a27d37a37a1d68b4739be306b1a7a)] - chore: fix issue template (#3369) (Suyi <>) +- [[`ef73396a5`](http://github.com/eggjs/egg/commit/ef73396a5828c6b4e55c85cd2b27c3830bd306e5)] - docs: improve debug docs (#3370) (TZ | 天猪 <>) +- [[`874e57fda`](http://github.com/eggjs/egg/commit/874e57fda480d3295c1b1b30198ca3493f57814d)] - docs(sequelize): fix init (#3372) (Yiyu He <>) +- [[`b2152c56f`](http://github.com/eggjs/egg/commit/b2152c56f525a87fe0c1cfe66949005f308e1569)] - Chore: Fix some typo translations (#3361) (Maledong <>) +- [[`d275929d1`](http://github.com/eggjs/egg/commit/d275929d17830c95a2c828611b5ca54ffb747270)] - docs(boot): update app start document (#3348) (Yiyu He <>) +- [[`9a8652beb`](http://github.com/eggjs/egg/commit/9a8652bebc29f3d097039196b10daa2575f49695)] - Fix: Change the diagram of "starting process" (#3358) (Maledong <>) +- [[`ac0f13bc6`](http://github.com/eggjs/egg/commit/ac0f13bc604ebfc08185b336a106ec7e5d1bc98f)] - Chore: Add missing links for "Sails" and union the spellings of "Plugin" (#3356) (Maledong <>) +- [[`cd52b063b`](http://github.com/eggjs/egg/commit/cd52b063b60e15bc78c440fdebc00ddd3dca9909)] - docs(cluster-and-ipc.md): fix typos and formatting errors (#3357) (Darren Poon <>) +- [[`37e3c1aba`](http://github.com/eggjs/egg/commit/37e3c1abab31f47fc492574464657a57ff686b2b)] - Chroe: Fix something in articles (#3349) (Maledong <>) ## 2018-12-20, Version 2.14.2 @atian25 ### Notable changes -* **fixes** - * fix d.ts context declaration not works +- **fixes** + - fix d.ts context declaration not works -* **docs** - * more document improvement +- **docs** + - more document improvement ### Commits - * [[`edfe66093`](http://github.com/eggjs/egg/commit/edfe66093c9ffe730ffd9804da1e2b264a48c38e)] - fix: Add comments for re-writing properties from Koa (#3332) (Maledong <>) - * [[`f312db78f`](http://github.com/eggjs/egg/commit/f312db78fc330da2bfe6efdb0f095d7b3b363beb)] - fix: fix context declaration not works (#3329) (Axes <>) - * [[`ef47a2746`](http://github.com/eggjs/egg/commit/ef47a274625a6ae8696857bef01b2c679dd65395)] - docs: fix config heading level (#3327) (Suyi <>) - * [[`cddd91ded`](http://github.com/eggjs/egg/commit/cddd91ded2fac1395487e2847caaf92afaafcf8e)] - chore: adjust template (TZ <>) - * [[`7319727a0`](http://github.com/eggjs/egg/commit/7319727a0b8a4fa210746ac201631a4b7db4359b)] - chore: Update issue templates (#3326) (TZ | 天猪 <>) - * [[`0cb246e26`](http://github.com/eggjs/egg/commit/0cb246e2663a288395a013ee78a1b34ab5b7c641)] - doc: Fix some translations with some icons (#3315) (Maledong <>) - * [[`9dc20377e`](http://github.com/eggjs/egg/commit/9dc20377e18e53278bcfac037e15a5a761cccdb3)] - doc: session special usage tip (#3304) (Jerry Wu <>) - * [[`6f4e91274`](http://github.com/eggjs/egg/commit/6f4e91274daa0685ba0ed8983ad5b6fd457322bc)] - docs: Update httpclient.md (#3276) (Albert <>) - * [[`64e88abfd`](http://github.com/eggjs/egg/commit/64e88abfd24d50096aa2d4ef442aafd46101429a)] - docs(egg-passport): add redirection desc while auth succeed (#3260) (Suyi <>) + +- [[`edfe66093`](http://github.com/eggjs/egg/commit/edfe66093c9ffe730ffd9804da1e2b264a48c38e)] - fix: Add comments for re-writing properties from Koa (#3332) (Maledong <>) +- [[`f312db78f`](http://github.com/eggjs/egg/commit/f312db78fc330da2bfe6efdb0f095d7b3b363beb)] - fix: fix context declaration not works (#3329) (Axes <>) +- [[`ef47a2746`](http://github.com/eggjs/egg/commit/ef47a274625a6ae8696857bef01b2c679dd65395)] - docs: fix config heading level (#3327) (Suyi <>) +- [[`cddd91ded`](http://github.com/eggjs/egg/commit/cddd91ded2fac1395487e2847caaf92afaafcf8e)] - chore: adjust template (TZ <>) +- [[`7319727a0`](http://github.com/eggjs/egg/commit/7319727a0b8a4fa210746ac201631a4b7db4359b)] - chore: Update issue templates (#3326) (TZ | 天猪 <>) +- [[`0cb246e26`](http://github.com/eggjs/egg/commit/0cb246e2663a288395a013ee78a1b34ab5b7c641)] - doc: Fix some translations with some icons (#3315) (Maledong <>) +- [[`9dc20377e`](http://github.com/eggjs/egg/commit/9dc20377e18e53278bcfac037e15a5a761cccdb3)] - doc: session special usage tip (#3304) (Jerry Wu <>) +- [[`6f4e91274`](http://github.com/eggjs/egg/commit/6f4e91274daa0685ba0ed8983ad5b6fd457322bc)] - docs: Update httpclient.md (#3276) (Albert <>) +- [[`64e88abfd`](http://github.com/eggjs/egg/commit/64e88abfd24d50096aa2d4ef442aafd46101429a)] - docs(egg-passport): add redirection desc while auth succeed (#3260) (Suyi <>) ## 2018-11-24, Version 2.14.1 @atian25 ### Notable changes -* **fixes** - * remove timeout log msg +- **fixes** + - remove timeout log msg -* **others** - * use circular-json-for-egg to remove deprecate message +- **others** + - use circular-json-for-egg to remove deprecate message ### Commits - * [[`0fb5a96c0`](http://github.com/eggjs/egg/commit/0fb5a96c023e916cb9c14c5960df62547ed391d8)] - fix: remove timeout log msg (#3229) (TZ | 天猪 <>) - * [[`de81caef1`](http://github.com/eggjs/egg/commit/de81caef1d91c229effadd25ddf752297c2a08f5)] - deps: use circular-json-for-egg to remove deprecate message (#3211) (Yiyu He <>) +- [[`0fb5a96c0`](http://github.com/eggjs/egg/commit/0fb5a96c023e916cb9c14c5960df62547ed391d8)] - fix: remove timeout log msg (#3229) (TZ | 天猪 <>) +- [[`de81caef1`](http://github.com/eggjs/egg/commit/de81caef1d91c229effadd25ddf752297c2a08f5)] - deps: use circular-json-for-egg to remove deprecate message (#3211) (Yiyu He <>) ## 2018-11-17, Version 2.14.0 @dead-horse ### Notable changes -* **features** - * add create anonymous context to agent - * support server timeout +- **features** + - add create anonymous context to agent + - support server timeout -* **fixes** - * curl: allow request timeout bigger than agent timeout - * triggerServerDidReady should be triggered only once +- **fixes** + - curl: allow request timeout bigger than agent timeout + - triggerServerDidReady should be triggered only once ### Commits - * [[`db999d3f7`](http://github.com/eggjs/egg/commit/db999d3f7afa210c855f3f1a4518e83f7d8c1dc6)] - docs: add serverTimeout to d.ts (#3200) (TZ | 天猪 <>) - * [[`a43fef4e1`](http://github.com/eggjs/egg/commit/a43fef4e1828937d3d84469989582df273de1493)] - docs(index.d.ts): curl 增加泛型 (#3197) (The Rock <>) - * [[`d40124a25`](http://github.com/eggjs/egg/commit/d40124a25fcd1b52ab862ee297139a022458b81d)] - feat: add create anonymous context to agent (#3193) (Hongcai Deng <>) - * [[`9dfd19ead`](http://github.com/eggjs/egg/commit/9dfd19eada8bae7be212155a2989d0ccc410e8eb)] - fix: triggerServerDidReady should be triggered only once (#3190) (killa <>) - * [[`7802528e1`](http://github.com/eggjs/egg/commit/7802528e122691eb2cb78174e1c1490d0a382c08)] - feat: support server timeout (#3133) (TZ | -天猪 <>) - * [[`ff79101b5`](http://github.com/eggjs/egg/commit/ff79101b592d59ad12d110dd26dd7fa3d044b968)] - docs: Update service.md (#3191) (肖金 <>) - * [[`327fa174f`](http://github.com/eggjs/egg/commit/327fa174ffd74a67a77520d839eac282c916e8c0)] - fix: allow request timeout bigger than agent timeout (#3146) (fengmk2 <>) - * [[`86093c03a`](http://github.com/eggjs/egg/commit/86093c03a822a2b925de94cfda96198dc8159ade)] - docs: remove promo logo (#3176) (Suyi <>) +- [[`db999d3f7`](http://github.com/eggjs/egg/commit/db999d3f7afa210c855f3f1a4518e83f7d8c1dc6)] - docs: add serverTimeout to d.ts (#3200) (TZ | 天猪 <>) +- [[`a43fef4e1`](http://github.com/eggjs/egg/commit/a43fef4e1828937d3d84469989582df273de1493)] - docs(index.d.ts): curl 增加泛型 (#3197) (The Rock <>) +- [[`d40124a25`](http://github.com/eggjs/egg/commit/d40124a25fcd1b52ab862ee297139a022458b81d)] - feat: add create anonymous context to agent (#3193) (Hongcai Deng <>) +- [[`9dfd19ead`](http://github.com/eggjs/egg/commit/9dfd19eada8bae7be212155a2989d0ccc410e8eb)] - fix: triggerServerDidReady should be triggered only once (#3190) (killa <>) +- [[`7802528e1`](http://github.com/eggjs/egg/commit/7802528e122691eb2cb78174e1c1490d0a382c08)] - feat: support server timeout (#3133) (TZ | + 天猪 <>) +- [[`ff79101b5`](http://github.com/eggjs/egg/commit/ff79101b592d59ad12d110dd26dd7fa3d044b968)] - docs: Update service.md (#3191) (肖金 <>) +- [[`327fa174f`](http://github.com/eggjs/egg/commit/327fa174ffd74a67a77520d839eac282c916e8c0)] - fix: allow request timeout bigger than agent timeout (#3146) (fengmk2 <>) +- [[`86093c03a`](http://github.com/eggjs/egg/commit/86093c03a822a2b925de94cfda96198dc8159ade)] - docs: remove promo logo (#3176) (Suyi <>) ## 2018-11-07, Version 2.13.0 @mansonchor ### Notable changes -* **feature** - * emit event when runInBackground catch error - -* **perf** - * better TypeScript support +- **feature** + - emit event when runInBackground catch error -* **docs** - * supplement documentation +- **perf** + - better TypeScript support +- **docs** + - supplement documentation ### Commits - * [[`03378b8c3`](https://github.com/mansonchor/egg.git/commit/03378b8c3e48e7000a580a4acf5375f9ffcac4dc)] - docs(plugin.md): fix 'path' declaration example (#3152) (maigozhang <>) - * [[`3c25221bd`](https://github.com/mansonchor/egg.git/commit/3c25221bd24a0a39cd06540fad46884e4dda363c)] - chore: use is.string() in utils.js for consistency (#3153) (ZYSzys <>) - * [[`a9b0fcec6`](https://github.com/mansonchor/egg.git/commit/a9b0fcec636f7241d0f578dca6b99444dabfeb83)] - chore(typings): add method `beforeClose` in index.d.ts (#3120) (Erona <>) - * [[`4709db746`](https://github.com/mansonchor/egg.git/commit/4709db746d8f97de99c04558f1ba86443e394668)] - feature(context): emit event when runInBackground catch error (#3118) (mansonchor <>) - * [[`e1dc2a7a4`](https://github.com/mansonchor/egg.git/commit/e1dc2a7a409a8bf56a817773229d5fc6dcde796b)] - docs: add promo logo (#3113) (Haoliang Gao <>) - * [[`51e9c1578`](https://github.com/mansonchor/egg.git/commit/51e9c1578496ed2afb44c47fdfd77867a95fec52)] - chore(typings): add interface IBoot (#3098) (killa <>) - * [[`8052d7ff7`](https://github.com/mansonchor/egg.git/commit/8052d7ff7bf6278e8ce4b4de46e0e6324d0d3861)] - doc: Update the `configWillLoad` explainations (#3116) (Maledong <>) - * [[`c3c4e2e3e`](https://github.com/mansonchor/egg.git/commit/c3c4e2e3e04a924595d6837ab15c7b292e3529f6)] - docs: add configWillLoad to lifecycle (#3101) (fengmk2 <>) - * [[`4abdb4980`](https://github.com/mansonchor/egg.git/commit/4abdb49801ebb3075b408d6fb3b72eba1a70c056)] - docs(CONTRIBUTION): Add missing link for `Accquire the submitted files` (#3102) (Maledong <>) - * [[`c7061ec62`](https://github.com/mansonchor/egg.git/commit/c7061ec6255faa250c6565a4c102f64c0498683c)] - fix(docs): Grammar of "lots of" (#3100) (waiting <>) - * [[`92181e83f`](https://github.com/mansonchor/egg.git/commit/92181e83f98d55bd1a796a871ab5d438d02c8e84)] - doc (CONTRIBUTION): Add missing English translations and clearify dns (#3035) (Maledong <>) - * [[`0a7497987`](https://github.com/mansonchor/egg.git/commit/0a7497987067ce1c3376dfc30676c35f484a5ccc)] - doc(logger.md): Fix incorrect description on default log output level. (#3082) (TX-Kunkun <>) - +- [[`03378b8c3`](https://github.com/mansonchor/egg.git/commit/03378b8c3e48e7000a580a4acf5375f9ffcac4dc)] - docs(plugin.md): fix 'path' declaration example (#3152) (maigozhang <>) +- [[`3c25221bd`](https://github.com/mansonchor/egg.git/commit/3c25221bd24a0a39cd06540fad46884e4dda363c)] - chore: use is.string() in utils.js for consistency (#3153) (ZYSzys <>) +- [[`a9b0fcec6`](https://github.com/mansonchor/egg.git/commit/a9b0fcec636f7241d0f578dca6b99444dabfeb83)] - chore(typings): add method `beforeClose` in index.d.ts (#3120) (Erona <>) +- [[`4709db746`](https://github.com/mansonchor/egg.git/commit/4709db746d8f97de99c04558f1ba86443e394668)] - feature(context): emit event when runInBackground catch error (#3118) (mansonchor <>) +- [[`e1dc2a7a4`](https://github.com/mansonchor/egg.git/commit/e1dc2a7a409a8bf56a817773229d5fc6dcde796b)] - docs: add promo logo (#3113) (Haoliang Gao <>) +- [[`51e9c1578`](https://github.com/mansonchor/egg.git/commit/51e9c1578496ed2afb44c47fdfd77867a95fec52)] - chore(typings): add interface IBoot (#3098) (killa <>) +- [[`8052d7ff7`](https://github.com/mansonchor/egg.git/commit/8052d7ff7bf6278e8ce4b4de46e0e6324d0d3861)] - doc: Update the `configWillLoad` explainations (#3116) (Maledong <>) +- [[`c3c4e2e3e`](https://github.com/mansonchor/egg.git/commit/c3c4e2e3e04a924595d6837ab15c7b292e3529f6)] - docs: add configWillLoad to lifecycle (#3101) (fengmk2 <>) +- [[`4abdb4980`](https://github.com/mansonchor/egg.git/commit/4abdb49801ebb3075b408d6fb3b72eba1a70c056)] - docs(CONTRIBUTION): Add missing link for `Accquire the submitted files` (#3102) (Maledong <>) +- [[`c7061ec62`](https://github.com/mansonchor/egg.git/commit/c7061ec6255faa250c6565a4c102f64c0498683c)] - fix(docs): Grammar of "lots of" (#3100) (waiting <>) +- [[`92181e83f`](https://github.com/mansonchor/egg.git/commit/92181e83f98d55bd1a796a871ab5d438d02c8e84)] - doc (CONTRIBUTION): Add missing English translations and clearify dns (#3035) (Maledong <>) +- [[`0a7497987`](https://github.com/mansonchor/egg.git/commit/0a7497987067ce1c3376dfc30676c35f484a5ccc)] - doc(logger.md): Fix incorrect description on default log output level. (#3082) (TX-Kunkun <>) ## 2018-10-08, Version 2.12.0 @dead-horse ### Notable changes -* **feature** - * add Subscription base class on app instance +- **feature** + - add Subscription base class on app instance -* **fix** - * upgrade to egg-logger@2, don't write log when stream was destroyed. - * pin circular-json@0.5.5 to avoid output deprecate message - -* **docs** - * corrected lots of documentation errors, thanks @Maledong - * use egg-logger definition +- **fix** + - upgrade to egg-logger@2, don't write log when stream was destroyed. + - pin circular-json@0.5.5 to avoid output deprecate message +- **docs** + - corrected lots of documentation errors, thanks @Maledong + - use egg-logger definition ### Commits - * [[`eb1eae736`](http://github.com/eggjs/egg/commit/eb1eae736c0fc541e6d21fb726d52d971d6a95da)] - refactor(typescript): use egg-logger definition (#3078) (Haoliang Gao <>) - * [[`04d9a3b85`](http://github.com/eggjs/egg/commit/04d9a3b85ef54819c0ad3ac505e7806db6a7e9b3)] - deps: egg-logger@2 (#3073) (Yiyu He <>) - * [[`886d9ad8f`](http://github.com/eggjs/egg/commit/886d9ad8fd11e1fbbd1712dd53ef464658f525b5)] - feat: add Subscription base class on app instance (#3058) (fengmk2 <>) - * [[`4c6fb2a17`](http://github.com/eggjs/egg/commit/4c6fb2a175c2481aa61aaad131f6812517bc7022)] - doc (socket.io): Make 'uws' cannot use anymore clear (#3068) (Maledong <>) - * [[`0d6798d22`](http://github.com/eggjs/egg/commit/0d6798d22d0e5016b0f7f25e5fa15ffe6900e16c)] - docs (Controller.md): Add new feat description (#3066) (Maledong <>) - * [[`399902680`](http://github.com/eggjs/egg/commit/39990268081d1da3fdb2d575802ea46cdf67bcd5)] - doc(typescript.md): Clarify the middleware's usages (#3039) (Maledong <>) - * [[`6bf812f73`](http://github.com/eggjs/egg/commit/6bf812f73603e967e405a815dcb2cc94dcb8384c)] - chore: fix middleware docs typo (#3060) (TZ | 天猪 <>) - * [[`b13d904d3`](http://github.com/eggjs/egg/commit/b13d904d302639c3b6068f109d4bcfa5aff12c61)] - test: avoid DNS pollution on local env (#3034) (fengmk2 <>) - * [[`bace2433b`](http://github.com/eggjs/egg/commit/bace2433bcc96d1507403c34711b2a2e450e6a6a)] - fix: remove loader.loadBootHook (Yiyu He <>) - * [[`6a7db2a35`](http://github.com/eggjs/egg/commit/6a7db2a3591a03b187bc3b52c67b37fde7984d34)] - doc (objects.md): Fix number and code errors (#3029) (Maledong <>) - * [[`c65a64899`](http://github.com/eggjs/egg/commit/c65a648991900b95a8ef0b21dcd8e3f715523df7)] - doc (TypeScript): Formation errors with missing translations (#3020) (Maledong <>) - * [[`abd8d1286`](http://github.com/eggjs/egg/commit/abd8d12861e17ff8fe5e950d589c00d17625beae)] - deps: pin circular-json@0.5.5 to avoid output deprecate message (#3023) (Yiyu He <>) - * [[`e3ffcbe64`](http://github.com/eggjs/egg/commit/e3ffcbe6449b95b50ea40583a28383e734c72fe1)] - docs (typescript.md): Add missing trans in English for TypeScript (#2998) (Maledong <>) +- [[`eb1eae736`](http://github.com/eggjs/egg/commit/eb1eae736c0fc541e6d21fb726d52d971d6a95da)] - refactor(typescript): use egg-logger definition (#3078) (Haoliang Gao <>) +- [[`04d9a3b85`](http://github.com/eggjs/egg/commit/04d9a3b85ef54819c0ad3ac505e7806db6a7e9b3)] - deps: egg-logger@2 (#3073) (Yiyu He <>) +- [[`886d9ad8f`](http://github.com/eggjs/egg/commit/886d9ad8fd11e1fbbd1712dd53ef464658f525b5)] - feat: add Subscription base class on app instance (#3058) (fengmk2 <>) +- [[`4c6fb2a17`](http://github.com/eggjs/egg/commit/4c6fb2a175c2481aa61aaad131f6812517bc7022)] - doc (socket.io): Make 'uws' cannot use anymore clear (#3068) (Maledong <>) +- [[`0d6798d22`](http://github.com/eggjs/egg/commit/0d6798d22d0e5016b0f7f25e5fa15ffe6900e16c)] - docs (Controller.md): Add new feat description (#3066) (Maledong <>) +- [[`399902680`](http://github.com/eggjs/egg/commit/39990268081d1da3fdb2d575802ea46cdf67bcd5)] - doc(typescript.md): Clarify the middleware's usages (#3039) (Maledong <>) +- [[`6bf812f73`](http://github.com/eggjs/egg/commit/6bf812f73603e967e405a815dcb2cc94dcb8384c)] - chore: fix middleware docs typo (#3060) (TZ | 天猪 <>) +- [[`b13d904d3`](http://github.com/eggjs/egg/commit/b13d904d302639c3b6068f109d4bcfa5aff12c61)] - test: avoid DNS pollution on local env (#3034) (fengmk2 <>) +- [[`bace2433b`](http://github.com/eggjs/egg/commit/bace2433bcc96d1507403c34711b2a2e450e6a6a)] - fix: remove loader.loadBootHook (Yiyu He <>) +- [[`6a7db2a35`](http://github.com/eggjs/egg/commit/6a7db2a3591a03b187bc3b52c67b37fde7984d34)] - doc (objects.md): Fix number and code errors (#3029) (Maledong <>) +- [[`c65a64899`](http://github.com/eggjs/egg/commit/c65a648991900b95a8ef0b21dcd8e3f715523df7)] - doc (TypeScript): Formation errors with missing translations (#3020) (Maledong <>) +- [[`abd8d1286`](http://github.com/eggjs/egg/commit/abd8d12861e17ff8fe5e950d589c00d17625beae)] - deps: pin circular-json@0.5.5 to avoid output deprecate message (#3023) (Yiyu He <>) +- [[`e3ffcbe64`](http://github.com/eggjs/egg/commit/e3ffcbe6449b95b50ea40583a28383e734c72fe1)] - docs (typescript.md): Add missing trans in English for TypeScript (#2998) (Maledong <>) ## 2018-09-19, Version 2.11.2 @XadillaX ### Notable changes -* **fix** - * typescript: add missing 'ignore', 'match' -* **refactor** - * separate dumping config object and config file +- **fix** + - typescript: add missing 'ignore', 'match' +- **refactor** + - separate dumping config object and config file ### Commits - * [[`1d30166e0`](http://github.com/eggjs/egg/commit/1d30166e037e8890fc850e51bdba02af76772485)] - refactor: separate dumping config object and config file (#3014) (Khaidi Chu <>) - * [[`e3f183e96`](http://github.com/eggjs/egg/commit/e3f183e9658e603c74850376f2257bd88bc4a043)] - fix (typescript): Add missing 'ignore','match' (#3010) (Maledong <>) +- [[`1d30166e0`](http://github.com/eggjs/egg/commit/1d30166e037e8890fc850e51bdba02af76772485)] - refactor: separate dumping config object and config file (#3014) (Khaidi Chu <>) +- [[`e3f183e96`](http://github.com/eggjs/egg/commit/e3f183e9658e603c74850376f2257bd88bc4a043)] - fix (typescript): Add missing 'ignore','match' (#3010) (Maledong <>) ## 2018-09-14, Version 2.11.1 @popomore ### Notable changes -* **fix** - * httpclient: can't use runInBackground in agent +- **fix** + - httpclient: can't use runInBackground in agent -* **deps** - * upgrade to debug@4 and coffee@5 +- **deps** + - upgrade to debug@4 and coffee@5 ### Commits - * [[`eed74e861`](http://github.com/eggjs/egg/commit/eed74e8610e1ea189beed1c3526b38f0b59c48ab)] - chore: update deps, debug@4 and coffee@5 (#2995) (TZ | 天猪 <>) - * [[`a8a3dfb04`](http://github.com/eggjs/egg/commit/a8a3dfb04f11b1c48ed1f01154e4d4311bfafa4b)] - fix(httpclient): can't use runInBackground in agent (#3003) (Haoliang Gao <>) - * [[`4faf68f4b`](http://github.com/eggjs/egg/commit/4faf68f4b6dad160a151b3d76041a0521261b530)] - doc (loader.md): Add missing English translations (#2996) (Maledong <>) +- [[`eed74e861`](http://github.com/eggjs/egg/commit/eed74e8610e1ea189beed1c3526b38f0b59c48ab)] - chore: update deps, debug@4 and coffee@5 (#2995) (TZ | 天猪 <>) +- [[`a8a3dfb04`](http://github.com/eggjs/egg/commit/a8a3dfb04f11b1c48ed1f01154e4d4311bfafa4b)] - fix(httpclient): can't use runInBackground in agent (#3003) (Haoliang Gao <>) +- [[`4faf68f4b`](http://github.com/eggjs/egg/commit/4faf68f4b6dad160a151b3d76041a0521261b530)] - doc (loader.md): Add missing English translations (#2996) (Maledong <>) ## 2018-09-11, Version 2.11.0 @atian25 ### Notable changes -* **feature** - * support boot lifecycle, see https://github.com/eggjs/egg/issues/2520 - * `dnshttpclient` now use async function instead of Promise - -* **fix** - * don't log when rawPacket is empty - -* **docs** - * add sequelize guide docs - * more document and typings improvement - -### Commits - - * [[`0d876c71a`](http://github.com/eggjs/egg/commit/0d876c71a9c4862b93cb039f564ae3d3171e1cad)] - feat: support boot lifecyle (#2972) (killa <>) - * [[`b02ce1547`](http://github.com/eggjs/egg/commit/b02ce154777fc78a6d344fe45d915d013096bea3)] - chroe(doc): Fix some typos (#2988) (Maledong <>) - * [[`688067ae0`](http://github.com/eggjs/egg/commit/688067ae09071316cbf5310b17d92d4fec39b42a)] - docs: fix 2 typos (#2982) (Jeff <>) - * [[`a719fd345`](http://github.com/eggjs/egg/commit/a719fd34507ebbfcf800768fb58adc81aa9c5e36)] - docs: Fix and add missing typos (#2935) (Maledong <>) - * [[`815c27879`](http://github.com/eggjs/egg/commit/815c278792e94ccf85822b3496f10396236e6628)] - fix (typings): Upgrade to the latest version of 'egg-cookie' to fetch (#2958) (Maledong <>) - * [[`a2df5ad13`](http://github.com/eggjs/egg/commit/a2df5ad137dea5faf7724d480edcc482a1df9393)] - docs: fixed typo. (#2961) (Ariel Yang <>) - * [[`b971e6633`](http://github.com/eggjs/egg/commit/b971e66336af4c8e241303866c8fa9acaaf4e66f)] - test: fix sitefile icon test (#2940) (Yiyu He <>) - * [[`81826ed1a`](http://github.com/eggjs/egg/commit/81826ed1a826a3436f8c42b7b5466295c60f241e)] - docs: fix link to angular commit-message-format (#2939) (Vincent <>) - * [[`45e302459`](http://github.com/eggjs/egg/commit/45e30245952619e4ed95867b2f76b0bdd06e94cc)] - fix: don't log when rawPacket is empty (#2924) (Haoliang Gao <>) - * [[`db1286de7`](http://github.com/eggjs/egg/commit/db1286de73de2cd987dc8f28c0616e9a683824a6)] - chore(typings): add class EggLoader (#2321) (waiting <>) - * [[`80528ccec`](http://github.com/eggjs/egg/commit/80528cceced500b5ae49ebf6d9df242ba2ce5ea4)] - refactor(dnshttpclient): use async function instead of Promise (#2774) (Haoliang Gao <>) - * [[`fe9e95654`](http://github.com/eggjs/egg/commit/fe9e9565472c7de9ff8dfb8894917764fe26fa0b)] - doc (package.json,README.zh-CN): Fix some typos (#2927) (Maledong <>) - * [[`289e96278`](http://github.com/eggjs/egg/commit/289e96278359a1468e366a6f3f7b2094dd3b7d6c)] - docs(sequelize): hostname shoule be host (#2921) (Will <<1078954008@qq.com>>) - * [[`72cd808b8`](http://github.com/eggjs/egg/commit/72cd808b86f37847cf340d88ec4eb73b9d7a7aa0)] - docs: fix sequelize link (#2909) (Yiyu He <>) - * [[`ae9ec30b4`](http://github.com/eggjs/egg/commit/ae9ec30b410bba3f8a99ba741e59fdb13e51c806)] - docs: add sequelize (#2902) (Yiyu He <>) - * [[`68135608b`](http://github.com/eggjs/egg/commit/68135608b3518b7d3dbd852453061179f63d5e4f)] - docs(deployment): fix typo on grep (#2898) (Baffin Lee <>) - * [[`6bfe70b3d`](http://github.com/eggjs/egg/commit/6bfe70b3d64206c85dea19c308abb40c46c6e347)] - doc (en,zh-cn): Fix translations error (#2885) (Maledong <>) - * [[`96ed020ce`](http://github.com/eggjs/egg/commit/96ed020ce04919049181808cee217029586d11c3)] - docs: fix config and socketio error (#2884) (Suyi <>) - +- **feature** + - support boot lifecycle, see https://github.com/eggjs/egg/issues/2520 + - `dnshttpclient` now use async function instead of Promise + +- **fix** + - don't log when rawPacket is empty + +- **docs** + - add sequelize guide docs + - more document and typings improvement + +### Commits + +- [[`0d876c71a`](http://github.com/eggjs/egg/commit/0d876c71a9c4862b93cb039f564ae3d3171e1cad)] - feat: support boot lifecyle (#2972) (killa <>) +- [[`b02ce1547`](http://github.com/eggjs/egg/commit/b02ce154777fc78a6d344fe45d915d013096bea3)] - chroe(doc): Fix some typos (#2988) (Maledong <>) +- [[`688067ae0`](http://github.com/eggjs/egg/commit/688067ae09071316cbf5310b17d92d4fec39b42a)] - docs: fix 2 typos (#2982) (Jeff <>) +- [[`a719fd345`](http://github.com/eggjs/egg/commit/a719fd34507ebbfcf800768fb58adc81aa9c5e36)] - docs: Fix and add missing typos (#2935) (Maledong <>) +- [[`815c27879`](http://github.com/eggjs/egg/commit/815c278792e94ccf85822b3496f10396236e6628)] - fix (typings): Upgrade to the latest version of 'egg-cookie' to fetch (#2958) (Maledong <>) +- [[`a2df5ad13`](http://github.com/eggjs/egg/commit/a2df5ad137dea5faf7724d480edcc482a1df9393)] - docs: fixed typo. (#2961) (Ariel Yang <>) +- [[`b971e6633`](http://github.com/eggjs/egg/commit/b971e66336af4c8e241303866c8fa9acaaf4e66f)] - test: fix sitefile icon test (#2940) (Yiyu He <>) +- [[`81826ed1a`](http://github.com/eggjs/egg/commit/81826ed1a826a3436f8c42b7b5466295c60f241e)] - docs: fix link to angular commit-message-format (#2939) (Vincent <>) +- [[`45e302459`](http://github.com/eggjs/egg/commit/45e30245952619e4ed95867b2f76b0bdd06e94cc)] - fix: don't log when rawPacket is empty (#2924) (Haoliang Gao <>) +- [[`db1286de7`](http://github.com/eggjs/egg/commit/db1286de73de2cd987dc8f28c0616e9a683824a6)] - chore(typings): add class EggLoader (#2321) (waiting <>) +- [[`80528ccec`](http://github.com/eggjs/egg/commit/80528cceced500b5ae49ebf6d9df242ba2ce5ea4)] - refactor(dnshttpclient): use async function instead of Promise (#2774) (Haoliang Gao <>) +- [[`fe9e95654`](http://github.com/eggjs/egg/commit/fe9e9565472c7de9ff8dfb8894917764fe26fa0b)] - doc (package.json,README.zh-CN): Fix some typos (#2927) (Maledong <>) +- [[`289e96278`](http://github.com/eggjs/egg/commit/289e96278359a1468e366a6f3f7b2094dd3b7d6c)] - docs(sequelize): hostname shoule be host (#2921) (Will <<1078954008@qq.com>>) +- [[`72cd808b8`](http://github.com/eggjs/egg/commit/72cd808b86f37847cf340d88ec4eb73b9d7a7aa0)] - docs: fix sequelize link (#2909) (Yiyu He <>) +- [[`ae9ec30b4`](http://github.com/eggjs/egg/commit/ae9ec30b410bba3f8a99ba741e59fdb13e51c806)] - docs: add sequelize (#2902) (Yiyu He <>) +- [[`68135608b`](http://github.com/eggjs/egg/commit/68135608b3518b7d3dbd852453061179f63d5e4f)] - docs(deployment): fix typo on grep (#2898) (Baffin Lee <>) +- [[`6bfe70b3d`](http://github.com/eggjs/egg/commit/6bfe70b3d64206c85dea19c308abb40c46c6e347)] - doc (en,zh-cn): Fix translations error (#2885) (Maledong <>) +- [[`96ed020ce`](http://github.com/eggjs/egg/commit/96ed020ce04919049181808cee217029586d11c3)] - docs: fix config and socketio error (#2884) (Suyi <>) ## 2018-08-06, Version 2.10.0 @fengmk2 ### Notable changes -* **feature** - * allow runInBackground reuse on plugins - * use Math.floor instead of parseInt - -* **fix** - * use cache-content-type - -* **docs** - * add lifecycle doc - * add sequelize guide - * add allowDebugAtProd in document - * egg-scripts support windows - * schedule add env description - * more document and typings improvement - -### Commits - - * [[`ff7431d5c`](http://github.com/eggjs/egg/commit/ff7431d5c4ea1e1d40fd7e3656dc5ab52ca55726)] - feat: allow runInBackground reuse on plugins (#2872) (fengmk2 <>) - * [[`422b342b1`](http://github.com/eggjs/egg/commit/422b342b1fa419db145323927f4f2d2a8996b7fb)] - feat: Update index.d.ts (#2853) (Ben <>) - * [[`2ca8f0184`](http://github.com/eggjs/egg/commit/2ca8f018473274fa544234c91fc608fa9bf09032)] - feat(typings): define Messenger['on'] and Messenger['once'] (#2763) (waiting <>) - * [[`9f8926d7c`](http://github.com/eggjs/egg/commit/9f8926d7cc55ae103b6a37751538870cc70aa12d)] - fix: use cache-content-type (#2793) (Yiyu He <>) - * [[`033fe0ce1`](http://github.com/eggjs/egg/commit/033fe0ce1d39bd63346de1ec60c97b159be867aa)] - docs: optimize egg-validate usage (#2852) (Sean Zou <<405495715@qq.com>>) - * [[`c0b0bb834`](http://github.com/eggjs/egg/commit/c0b0bb8345df83bbd2949b0af34bb397b5185e17)] - docs(session): fix bug in example code of modify session value (#2824) (Baffin Lee <>) - * [[`b55b303ed`](http://github.com/eggjs/egg/commit/b55b303eddbaf545cdb06fd81df624fd3070110a)] - test: test on travis with node 10 (#2461) (Yiyu He <>) - * [[`38a472f24`](http://github.com/eggjs/egg/commit/38a472f24cf68acb9c64fafa2e4374115d578220)] - docs: add allowDebugAtProd in document (#2803) (Yiyu He <>) - * [[`e86669937`](http://github.com/eggjs/egg/commit/e866699379bc570f8bfcef9a090f1bdb5cddee32)] - perf: use Math.floor instead of parseInt (Eason <>) - * [[`67d538e0e`](http://github.com/eggjs/egg/commit/67d538e0e175e96fe2a64b9c8d17b063537236f7)] - docs(plugin): add details for plugin.js (#2780) (TZ | 天猪 <>) - * [[`8d0b29cc9`](http://github.com/eggjs/egg/commit/8d0b29cc9b0a3b8eefad1ab64a05478c81709144)] - docs(deployment): egg-scripts support windows (#2788) (Baffin Lee <>) - * [[`aaf8faf4f`](http://github.com/eggjs/egg/commit/aaf8faf4fd8d813c7938baa1533d768b9d205fc7)] - test: skip test (#2773) (Haoliang Gao <>) - * [[`eb70335bd`](http://github.com/eggjs/egg/commit/eb70335bd61b6887ffeb33f103340b89c857312a)] - docs(schedule): add env description (#2753) (TZ | 天猪 <>) - * [[`ef20ff756`](http://github.com/eggjs/egg/commit/ef20ff75633b6e83b115d32af603d0f4f34cb1e1)] - docs: add http://www.sofastack.tech (#2752) (Haoliang Gao <>) - * [[`1ecb521c5`](http://github.com/eggjs/egg/commit/1ecb521c50b6238397f9a0b628448c0d2b5ec4fa)] - doc: add lifecyle doc (#2708) (killa <>) - * [[`7930f0419`](http://github.com/eggjs/egg/commit/7930f0419fee741bcf6de73693bcdf1e9986f31e)] - docs: fix ws engine error (#2717) (Suyi <>) +- **feature** + - allow runInBackground reuse on plugins + - use Math.floor instead of parseInt + +- **fix** + - use cache-content-type + +- **docs** + - add lifecycle doc + - add sequelize guide + - add allowDebugAtProd in document + - egg-scripts support windows + - schedule add env description + - more document and typings improvement + +### Commits + +- [[`ff7431d5c`](http://github.com/eggjs/egg/commit/ff7431d5c4ea1e1d40fd7e3656dc5ab52ca55726)] - feat: allow runInBackground reuse on plugins (#2872) (fengmk2 <>) +- [[`422b342b1`](http://github.com/eggjs/egg/commit/422b342b1fa419db145323927f4f2d2a8996b7fb)] - feat: Update index.d.ts (#2853) (Ben <>) +- [[`2ca8f0184`](http://github.com/eggjs/egg/commit/2ca8f018473274fa544234c91fc608fa9bf09032)] - feat(typings): define Messenger['on'] and Messenger['once'] (#2763) (waiting <>) +- [[`9f8926d7c`](http://github.com/eggjs/egg/commit/9f8926d7cc55ae103b6a37751538870cc70aa12d)] - fix: use cache-content-type (#2793) (Yiyu He <>) +- [[`033fe0ce1`](http://github.com/eggjs/egg/commit/033fe0ce1d39bd63346de1ec60c97b159be867aa)] - docs: optimize egg-validate usage (#2852) (Sean Zou <<405495715@qq.com>>) +- [[`c0b0bb834`](http://github.com/eggjs/egg/commit/c0b0bb8345df83bbd2949b0af34bb397b5185e17)] - docs(session): fix bug in example code of modify session value (#2824) (Baffin Lee <>) +- [[`b55b303ed`](http://github.com/eggjs/egg/commit/b55b303eddbaf545cdb06fd81df624fd3070110a)] - test: test on travis with node 10 (#2461) (Yiyu He <>) +- [[`38a472f24`](http://github.com/eggjs/egg/commit/38a472f24cf68acb9c64fafa2e4374115d578220)] - docs: add allowDebugAtProd in document (#2803) (Yiyu He <>) +- [[`e86669937`](http://github.com/eggjs/egg/commit/e866699379bc570f8bfcef9a090f1bdb5cddee32)] - perf: use Math.floor instead of parseInt (Eason <>) +- [[`67d538e0e`](http://github.com/eggjs/egg/commit/67d538e0e175e96fe2a64b9c8d17b063537236f7)] - docs(plugin): add details for plugin.js (#2780) (TZ | 天猪 <>) +- [[`8d0b29cc9`](http://github.com/eggjs/egg/commit/8d0b29cc9b0a3b8eefad1ab64a05478c81709144)] - docs(deployment): egg-scripts support windows (#2788) (Baffin Lee <>) +- [[`aaf8faf4f`](http://github.com/eggjs/egg/commit/aaf8faf4fd8d813c7938baa1533d768b9d205fc7)] - test: skip test (#2773) (Haoliang Gao <>) +- [[`eb70335bd`](http://github.com/eggjs/egg/commit/eb70335bd61b6887ffeb33f103340b89c857312a)] - docs(schedule): add env description (#2753) (TZ | 天猪 <>) +- [[`ef20ff756`](http://github.com/eggjs/egg/commit/ef20ff75633b6e83b115d32af603d0f4f34cb1e1)] - docs: add http://www.sofastack.tech (#2752) (Haoliang Gao <>) +- [[`1ecb521c5`](http://github.com/eggjs/egg/commit/1ecb521c50b6238397f9a0b628448c0d2b5ec4fa)] - doc: add lifecyle doc (#2708) (killa <>) +- [[`7930f0419`](http://github.com/eggjs/egg/commit/7930f0419fee741bcf6de73693bcdf1e9986f31e)] - docs: fix ws engine error (#2717) (Suyi <>) ## 2018-06-14, Version 2.9.1 @dead-horse ### Notable changes -* **perf** - * improve set type performance +- **perf** + - improve set type performance -* **docs** - * fix socketio's browser demo - * add Messenger in tsd +- **docs** + - fix socketio's browser demo + - add Messenger in tsd ### Commits - * [[`1a820bd44`](http://github.com/eggjs/egg/commit/1a820bd4408b36cf3e48eda62f392006081c17a3)] - perf: improve set type performance by lru cache (#2697) (fengmk2 <>) - * [[`239ce03ef`](http://github.com/eggjs/egg/commit/239ce03efaf60d3d961ced29cf4bf95e44bde2db)] - docs: fix socketio's browser demo (#2645) (xcold <>) - * [[`73ca1b7a3`](http://github.com/eggjs/egg/commit/73ca1b7a3ef6546d4f8a3d227055121a93b80188)] - chore(typings): add Messenger (#2688) (waiting <>) +- [[`1a820bd44`](http://github.com/eggjs/egg/commit/1a820bd4408b36cf3e48eda62f392006081c17a3)] - perf: improve set type performance by lru cache (#2697) (fengmk2 <>) +- [[`239ce03ef`](http://github.com/eggjs/egg/commit/239ce03efaf60d3d961ced29cf4bf95e44bde2db)] - docs: fix socketio's browser demo (#2645) (xcold <>) +- [[`73ca1b7a3`](http://github.com/eggjs/egg/commit/73ca1b7a3ef6546d4f8a3d227055121a93b80188)] - chore(typings): add Messenger (#2688) (waiting <>) ## 2018-06-01, Version 2.9.0 @popomore ### Notable changes -* **feature** - * dump timing data for loader +- **feature** + - dump timing data for loader -* **fix** - * the default value of config.allowDebugAtProd is false - * make definition of app.locals and ctx.locals definitions merge available - * add key any to Context in typescript define +- **fix** + - the default value of config.allowDebugAtProd is false + - make definition of app.locals and ctx.locals definitions merge available + - add key any to Context in typescript define -* **docs** - * more document improvement +- **docs** + - more document improvement ### Commits - * [[`e5737d545`](http://github.com/eggjs/egg/commit/e5737d5455d536b908f37ba367446e511f30e663)] - fix: add key any to Context (#2650) (Axes <>) - * [[`65a43aa9e`](http://github.com/eggjs/egg/commit/65a43aa9e47ad2f799e328e4e0ab91a63669c5e3)] - feat: dump timing data for loader (#2521) (#2621) (Haoliang Gao <>) - * [[`48c6d3c9d`](http://github.com/eggjs/egg/commit/48c6d3c9d524e1cbba3e301e6613436741696cc0)] - fix: typo (#2615) (Yanan Che <>) - * [[`c91e67cc0`](http://github.com/eggjs/egg/commit/c91e67cc0246a22efee126ebd01866b05b8312dc)] - docs(logger): the unit of maxFileSize should be byte (#2575) (Haoliang Gao <>) - * [[`26c274174`](http://github.com/eggjs/egg/commit/26c274174c9a48ef1636933fbb2be9777d38f522)] - docs: tweek doc style (#2613) (Haoliang Gao <>) - * [[`3ee7fcf12`](http://github.com/eggjs/egg/commit/3ee7fcf1291a4968197fab4648e951176dfa2714)] - docs: fix quickstart typo error (#2578) (Zhuxy <>) - * [[`8b7c8bd35`](http://github.com/eggjs/egg/commit/8b7c8bd35f8695f4459cfd623f9961c276e0d5a6)] - docs(d.ts): add property of EggAppConfig.development (#2561) (SinaVee <>) - * [[`16a61231d`](http://github.com/eggjs/egg/commit/16a61231d12c91ae609e68509d29aac669e1b83c)] - docs: add d.ts for bodyparser (#2548) (wangtao0101 <>) - * [[`e7696a7d2`](http://github.com/eggjs/egg/commit/e7696a7d2b4bc8eb6fb984aaaa0e0f2422d1c048)] - fix(d.ts): make app.locals and ctx.locals definitions merging available (#2546) (Tony Hawking <>) - * [[`e5d47524e`](http://github.com/eggjs/egg/commit/e5d47524ef96138172c86e774014a6b26d5cac09)] - chroe: Correct an error syntax of English (#2544) (DongWei <>) - * [[`c0f4bd12d`](http://github.com/eggjs/egg/commit/c0f4bd12d422554351b1d1e9866a7b9bbc444e76)] - fix: config.allowDebugAtProd default to false (ZhangJan <>) - * [[`0723cd230`](http://github.com/eggjs/egg/commit/0723cd230514b623c4454120dae988fd5a68ec44)] - docs(cookie): how to get frontend cookie (#2542) (Yiyu He <>) - * [[`9fea64ee9`](http://github.com/eggjs/egg/commit/9fea64ee993de7c3ee2e239d7bba91f5f3b3408a)] - docs: Fix an error link, change a comment into English (#2535) (DongWei <>) - * [[`e96ddb6a8`](http://github.com/eggjs/egg/commit/e96ddb6a884ef767c8653242c666dcc7381222b7)] - docs: Modifications of comments and full translations (DongWei <>) +- [[`e5737d545`](http://github.com/eggjs/egg/commit/e5737d5455d536b908f37ba367446e511f30e663)] - fix: add key any to Context (#2650) (Axes <>) +- [[`65a43aa9e`](http://github.com/eggjs/egg/commit/65a43aa9e47ad2f799e328e4e0ab91a63669c5e3)] - feat: dump timing data for loader (#2521) (#2621) (Haoliang Gao <>) +- [[`48c6d3c9d`](http://github.com/eggjs/egg/commit/48c6d3c9d524e1cbba3e301e6613436741696cc0)] - fix: typo (#2615) (Yanan Che <>) +- [[`c91e67cc0`](http://github.com/eggjs/egg/commit/c91e67cc0246a22efee126ebd01866b05b8312dc)] - docs(logger): the unit of maxFileSize should be byte (#2575) (Haoliang Gao <>) +- [[`26c274174`](http://github.com/eggjs/egg/commit/26c274174c9a48ef1636933fbb2be9777d38f522)] - docs: tweek doc style (#2613) (Haoliang Gao <>) +- [[`3ee7fcf12`](http://github.com/eggjs/egg/commit/3ee7fcf1291a4968197fab4648e951176dfa2714)] - docs: fix quickstart typo error (#2578) (Zhuxy <>) +- [[`8b7c8bd35`](http://github.com/eggjs/egg/commit/8b7c8bd35f8695f4459cfd623f9961c276e0d5a6)] - docs(d.ts): add property of EggAppConfig.development (#2561) (SinaVee <>) +- [[`16a61231d`](http://github.com/eggjs/egg/commit/16a61231d12c91ae609e68509d29aac669e1b83c)] - docs: add d.ts for bodyparser (#2548) (wangtao0101 <>) +- [[`e7696a7d2`](http://github.com/eggjs/egg/commit/e7696a7d2b4bc8eb6fb984aaaa0e0f2422d1c048)] - fix(d.ts): make app.locals and ctx.locals definitions merging available (#2546) (Tony Hawking <>) +- [[`e5d47524e`](http://github.com/eggjs/egg/commit/e5d47524ef96138172c86e774014a6b26d5cac09)] - chroe: Correct an error syntax of English (#2544) (DongWei <>) +- [[`c0f4bd12d`](http://github.com/eggjs/egg/commit/c0f4bd12d422554351b1d1e9866a7b9bbc444e76)] - fix: config.allowDebugAtProd default to false (ZhangJan <>) +- [[`0723cd230`](http://github.com/eggjs/egg/commit/0723cd230514b623c4454120dae988fd5a68ec44)] - docs(cookie): how to get frontend cookie (#2542) (Yiyu He <>) +- [[`9fea64ee9`](http://github.com/eggjs/egg/commit/9fea64ee993de7c3ee2e239d7bba91f5f3b3408a)] - docs: Fix an error link, change a comment into English (#2535) (DongWei <>) +- [[`e96ddb6a8`](http://github.com/eggjs/egg/commit/e96ddb6a884ef767c8653242c666dcc7381222b7)] - docs: Modifications of comments and full translations (DongWei <>) ## 2018-05-05, Version 2.8.1 @atian25 ### Notable changes -* **docs** - * fix missing d.ts +- **docs** + - fix missing d.ts ### Commits - * [[`20356bffc`](http://github.com/eggjs/egg/commit/20356bffcf7e99970b44f230a6fc2a8f9547a380)] - feat(d.ts): add createAnonymousContext & runInBackground (#2501) (Hengfei Zhuang <>) - * [[`c013ef3e6`](http://github.com/eggjs/egg/commit/c013ef3e64e049c6ef48e29d289f6d756b6ca1f7)] - feat(d.ts): add runSchedule & Subscription define (#2504) (Hengfei Zhuang <>) +- [[`20356bffc`](http://github.com/eggjs/egg/commit/20356bffcf7e99970b44f230a6fc2a8f9547a380)] - feat(d.ts): add createAnonymousContext & runInBackground (#2501) (Hengfei Zhuang <>) +- [[`c013ef3e6`](http://github.com/eggjs/egg/commit/c013ef3e64e049c6ef48e29d289f6d756b6ca1f7)] - feat(d.ts): add runSchedule & Subscription define (#2504) (Hengfei Zhuang <>) ## 2018-05-03, Version 2.8.0 @dead-horse ### Notable changes -* **feature** - * add time duration for dump config +- **feature** + - add time duration for dump config -* **fix** - * make singleton work for unextensible or frozen instance +- **fix** + - make singleton work for unextensible or frozen instance -* **docs** - * switch to English document - * add middleware to Application and other ts improvement (typescript) - * update wxapp-socket-io project to weapp.socket.io - * update title and remove unused files +- **docs** + - switch to English document + - add middleware to Application and other ts improvement (typescript) + - update wxapp-socket-io project to weapp.socket.io + - update title and remove unused files ### Commits - * [[`4b602d037`](http://github.com/eggjs/egg/commit/4b602d037554b72c8261b7abb7efd94f8f59f3fe)] - fix: make singleton work for unextensible or frozen instance (#2472) (Yiyu He <>) - * [[`824200c11`](http://github.com/eggjs/egg/commit/824200c11cac8e20b2c275daa7f5a4a365c71259)] - feat: add time duration for dump config (#2485) (Haoliang Gao <>) - * [[`73dac083d`](http://github.com/eggjs/egg/commit/73dac083d2a029f893e9b6737080c921027e308f)] - docs: update wxapp-socket-io project to weapp.socket.io (#2421) (liuguili <>) - * [[`1ada8e384`](http://github.com/eggjs/egg/commit/1ada8e3848be9f09680d7cac091fb14206df5a11)] - feat(d.ts): add middleware to Application and other ts improvement (#2465) (Axes <>) - * [[`437785315`](http://github.com/eggjs/egg/commit/437785315f28a828ea0cf7bece80223d5b796dc5)] - docs: fix the code error of LOCALS in view.md (#2464) (zjz19901029 <<346663801@qq.com>>) - * [[`f341b9fb8`](http://github.com/eggjs/egg/commit/f341b9fb8bdf36b6280500578e8448c59aec10f1)] - chore: update title and remove unused files (#2433) (TZ | -天猪 <>) - * [[`a5ab29cbd`](http://github.com/eggjs/egg/commit/a5ab29cbd1de0f5425019085258a496b4bce8b45)] - docs: switch to English document (#2426) (Haoliang Gao <>) - * [[`4ab7df25f`](http://github.com/eggjs/egg/commit/4ab7df25f152609d494745eac2794b78e66444f0)] - deps: update dependencies, add @types/urllib to autod config (#2423) (Yiyu He <>) +- [[`4b602d037`](http://github.com/eggjs/egg/commit/4b602d037554b72c8261b7abb7efd94f8f59f3fe)] - fix: make singleton work for unextensible or frozen instance (#2472) (Yiyu He <>) +- [[`824200c11`](http://github.com/eggjs/egg/commit/824200c11cac8e20b2c275daa7f5a4a365c71259)] - feat: add time duration for dump config (#2485) (Haoliang Gao <>) +- [[`73dac083d`](http://github.com/eggjs/egg/commit/73dac083d2a029f893e9b6737080c921027e308f)] - docs: update wxapp-socket-io project to weapp.socket.io (#2421) (liuguili <>) +- [[`1ada8e384`](http://github.com/eggjs/egg/commit/1ada8e3848be9f09680d7cac091fb14206df5a11)] - feat(d.ts): add middleware to Application and other ts improvement (#2465) (Axes <>) +- [[`437785315`](http://github.com/eggjs/egg/commit/437785315f28a828ea0cf7bece80223d5b796dc5)] - docs: fix the code error of LOCALS in view.md (#2464) (zjz19901029 <<346663801@qq.com>>) +- [[`f341b9fb8`](http://github.com/eggjs/egg/commit/f341b9fb8bdf36b6280500578e8448c59aec10f1)] - chore: update title and remove unused files (#2433) (TZ | + 天猪 <>) +- [[`a5ab29cbd`](http://github.com/eggjs/egg/commit/a5ab29cbd1de0f5425019085258a496b4bce8b45)] - docs: switch to English document (#2426) (Haoliang Gao <>) +- [[`4ab7df25f`](http://github.com/eggjs/egg/commit/4ab7df25f152609d494745eac2794b78e66444f0)] - deps: update dependencies, add @types/urllib to autod config (#2423) (Yiyu He <>) ## 2018-04-17, Version 2.7.1 @dead-horse ### Notable changes -* **fix** - * imporve compatibility of singleton +- **fix** + - imporve compatibility of singleton ### Commits - * [[`e4d219f`](http://github.com/eggjs/egg/commit/e4d219f1aaecbca13601c7813e57c67934e8c32b)] - fix: imporve compatibility of singleton (#2410) (Yiyu He <>) +- [[`e4d219f`](http://github.com/eggjs/egg/commit/e4d219f1aaecbca13601c7813e57c67934e8c32b)] - fix: imporve compatibility of singleton (#2410) (Yiyu He <>) ## 2018-04-16, Version 2.7.0 @dead-horse [DEPRECATED] ### Notable changes -* **feature** - * singleton support asynchronous create function +- **feature** + - singleton support asynchronous create function -* **fix** - * dump config support circular json +- **fix** + - dump config support circular json -* **docs** - * improve router and typescript +- **docs** + - improve router and typescript ### Commits - * [[`3d499a9`](http://github.com/eggjs/egg/commit/3d499a90bab7095569e115e223de40e63812f2f5)] - docs(plugin): add singleton support async create function (#2392) (Yiyu He <>) - * [[`05d925f`](http://github.com/eggjs/egg/commit/05d925fea4e0b2d8efa48cb01ced2133c0c059cd)] - docs: change English document on Readme (#2397) (Haoliang Gao <>) - * [[`590bd8c`](http://github.com/eggjs/egg/commit/590bd8cb400845706ec7cc84232b812cb468c8ac)] - fix: dumpConfig support circular json (#2394) (Yiyu He <>) - * [[`3a489b6`](http://github.com/eggjs/egg/commit/3a489b6f47b39ff2ec31efe936504918300b3f08)] - feat(singleton): support async create function (#2382) (Yiyu He <>) - * [[`a5b6731`](http://github.com/eggjs/egg/commit/a5b673133b35e9b005e19c1e3267a2ff3d58e32b)] - docs: chore for router and typescript (#2390) (TZ | 天猪 <>) - * [[`ee2d2b3`](http://github.com/eggjs/egg/commit/ee2d2b3c33671a822b45a6c474d3710aab5e70d5)] - docs(passport): translation for passport tutorial (#2235) (Cemre Mengu <>) - * [[`6fad4e1`](http://github.com/eggjs/egg/commit/6fad4e1bed3c388e964fc656244e5e606b258085)] - chore: update package.json for release (#2381) (TZ | 天猪 <>) +- [[`3d499a9`](http://github.com/eggjs/egg/commit/3d499a90bab7095569e115e223de40e63812f2f5)] - docs(plugin): add singleton support async create function (#2392) (Yiyu He <>) +- [[`05d925f`](http://github.com/eggjs/egg/commit/05d925fea4e0b2d8efa48cb01ced2133c0c059cd)] - docs: change English document on Readme (#2397) (Haoliang Gao <>) +- [[`590bd8c`](http://github.com/eggjs/egg/commit/590bd8cb400845706ec7cc84232b812cb468c8ac)] - fix: dumpConfig support circular json (#2394) (Yiyu He <>) +- [[`3a489b6`](http://github.com/eggjs/egg/commit/3a489b6f47b39ff2ec31efe936504918300b3f08)] - feat(singleton): support async create function (#2382) (Yiyu He <>) +- [[`a5b6731`](http://github.com/eggjs/egg/commit/a5b673133b35e9b005e19c1e3267a2ff3d58e32b)] - docs: chore for router and typescript (#2390) (TZ | 天猪 <>) +- [[`ee2d2b3`](http://github.com/eggjs/egg/commit/ee2d2b3c33671a822b45a6c474d3710aab5e70d5)] - docs(passport): translation for passport tutorial (#2235) (Cemre Mengu <>) +- [[`6fad4e1`](http://github.com/eggjs/egg/commit/6fad4e1bed3c388e964fc656244e5e606b258085)] - chore: update package.json for release (#2381) (TZ | 天猪 <>) ## 2018-04-12, Version 2.6.1 @atian25 ### Notable changes -* **docs** - * TypeScript Guide (#2324) - * fix d.ts with ts support - * docs improve +- **docs** + - TypeScript Guide (#2324) + - fix d.ts with ts support + - docs improve ### Commits - * [[`2998bf733`](http://github.com/eggjs/egg/commit/2998bf733268d4d88d5fc77e05943b3fa0f824d4)] - chore(typings): add index signature of EggAppConfig (#2359) (waiting <>) - * [[`5f2358bbd`](http://github.com/eggjs/egg/commit/5f2358bbdd6e21a1ab387a8425d0fefc30954227)] - docs: intro session.renew in the doc (#2375) (Yiyu He <>) - * [[`f0e7773f2`](http://github.com/eggjs/egg/commit/f0e7773f28eb7a233230a847ff2f8bc737aa3c01)] - docs: add TypeScript Guide (#2324) (TZ | 天猪 <>) - * [[`cd418f57a`](http://github.com/eggjs/egg/commit/cd418f57a843b504dcac6d8c25b99026e1edf072)] - docs(controller): add ctx.redirect (#2373) (Yiyu He <>) - * [[`2fafb16b8`](http://github.com/eggjs/egg/commit/2fafb16b8810e41b86d15f51257c2a0531c78357)] - docs(socketio): update demo & solve problem on chrome (#2354) (Suyi <>) - * [[`ba708ca4e`](http://github.com/eggjs/egg/commit/ba708ca4e911a345d2ee6aea5d4cf5845f93212b)] - feat: support customized client error (#2283) (Khaidi Chu <>) - * [[`8697140d6`](http://github.com/eggjs/egg/commit/8697140d6ab10f42980ea301e7122331b6e5573a)] - chore: add export to declarations (#2344) (Axes <>) - * [[`441884145`](http://github.com/eggjs/egg/commit/4418841452a20a4fcca212e17dad0fbe9ff97646)] - chore(typings): export PowerPartial (#2327) (waiting <>) - * [[`33d39519e`](http://github.com/eggjs/egg/commit/33d39519e1bd9bb1451776abe4986cdf4dee7626)] - docs(passport): config passport-github behind of proxy (#2318) (Suyi <>) - * [[`84e0dc4e7`](http://github.com/eggjs/egg/commit/84e0dc4e74e4e907d39b5485e1b19c3900aec393)] - fix(d.ts): add modifier to plugin and add middleware to config (#2322) (Axes <>) +- [[`2998bf733`](http://github.com/eggjs/egg/commit/2998bf733268d4d88d5fc77e05943b3fa0f824d4)] - chore(typings): add index signature of EggAppConfig (#2359) (waiting <>) +- [[`5f2358bbd`](http://github.com/eggjs/egg/commit/5f2358bbdd6e21a1ab387a8425d0fefc30954227)] - docs: intro session.renew in the doc (#2375) (Yiyu He <>) +- [[`f0e7773f2`](http://github.com/eggjs/egg/commit/f0e7773f28eb7a233230a847ff2f8bc737aa3c01)] - docs: add TypeScript Guide (#2324) (TZ | 天猪 <>) +- [[`cd418f57a`](http://github.com/eggjs/egg/commit/cd418f57a843b504dcac6d8c25b99026e1edf072)] - docs(controller): add ctx.redirect (#2373) (Yiyu He <>) +- [[`2fafb16b8`](http://github.com/eggjs/egg/commit/2fafb16b8810e41b86d15f51257c2a0531c78357)] - docs(socketio): update demo & solve problem on chrome (#2354) (Suyi <>) +- [[`ba708ca4e`](http://github.com/eggjs/egg/commit/ba708ca4e911a345d2ee6aea5d4cf5845f93212b)] - feat: support customized client error (#2283) (Khaidi Chu <>) +- [[`8697140d6`](http://github.com/eggjs/egg/commit/8697140d6ab10f42980ea301e7122331b6e5573a)] - chore: add export to declarations (#2344) (Axes <>) +- [[`441884145`](http://github.com/eggjs/egg/commit/4418841452a20a4fcca212e17dad0fbe9ff97646)] - chore(typings): export PowerPartial (#2327) (waiting <>) +- [[`33d39519e`](http://github.com/eggjs/egg/commit/33d39519e1bd9bb1451776abe4986cdf4dee7626)] - docs(passport): config passport-github behind of proxy (#2318) (Suyi <>) +- [[`84e0dc4e7`](http://github.com/eggjs/egg/commit/84e0dc4e74e4e907d39b5485e1b19c3900aec393)] - fix(d.ts): add modifier to plugin and add middleware to config (#2322) (Axes <>) ## 2018-04-04, Version 2.6.0 @atian25 ### Notable changes -* **feature** - * TypeScript tool support (#2272) +- **feature** + - TypeScript tool support (#2272) -* **docs** - * improve d.ts with ts support (#2306) - * docs improve and translation +- **docs** + - improve d.ts with ts support (#2306) + - docs improve and translation ### Commits - * [[`406142758`](http://github.com/eggjs/egg/commit/40614275845f49512e80d1c8c00d1997ee91b113)] - chore: improve d.ts with ts support (#2306) (Axes <>) - * [[`7fba689b7`](http://github.com/eggjs/egg/commit/7fba689b73fa46fdf7447844338a7f538ad78665)] - docs(controller): session example bug (#2313) (Suyi <>) - * [[`e0e7ed146`](http://github.com/eggjs/egg/commit/e0e7ed146adfe932558628b815caa2d8c64d6939)] - chore(typings): change export interface to class definition (#2293) (waiting <>) - * [[`161107929`](http://github.com/eggjs/egg/commit/1611079291ddcf8cc82dba40a2406dcad20b75b5)] - docs(plugin): add config notice for `addSingleton` function (#2305) (Shangbin Yang <>) - * [[`1c74a8491`](http://github.com/eggjs/egg/commit/1c74a84918869ec035c5767884501a87cce945d5)] - docs: add assets document (#2220) (Haoliang Gao <>) - * [[`e4531e563`](http://github.com/eggjs/egg/commit/e4531e563214472e54b4c467e0d2879e6390cb52)] - docs: EN translation for view plugin dev doc (#2240) (Cemre Mengu <>) - * [[`348ff18d8`](http://github.com/eggjs/egg/commit/348ff18d82e357d9bceba5136c339ef7dfb44bda)] - docs: EN translation for style guide doc (#2239) (Cemre Mengu <>) - * [[`d9c4ec2bb`](http://github.com/eggjs/egg/commit/d9c4ec2bbb3aa29ddcba2efceec6edfa879267d7)] - EN translation for resources doc (#2238) (Cemre Mengu <>) - * [[`46217a5d2`](http://github.com/eggjs/egg/commit/46217a5d2e451433ec86614cfb65336300a074d9)] - docs(security): add ssrf in security (#2274) (Yiyu He <>) - * [[`c3586eab5`](http://github.com/eggjs/egg/commit/c3586eab535ee540ffac664f0311c656ef7adca2)] - docs: deprecate ignoreJSON (#2270) (Yiyu He <>) - * [[`a86334c59`](http://github.com/eggjs/egg/commit/a86334c595530c5f4e9cf65204a4591dfd26bcf0)] - docs: example for custom id when mysql update (#2165) (OnedayLiu <>) - * [[`10327e185`](http://github.com/eggjs/egg/commit/10327e185015098c9c29747abbaf79a352f975d7)] - docs: EN translation for socketio tutorial doc (#2167) (Cemre Mengu <>) - * [[`5b059db6a`](http://github.com/eggjs/egg/commit/5b059db6a879abb3ffe7b30e95855afc8a660107)] - docs: add boilerplate type desc (#2250) (QiChang Li <>) - * [[`9007b5847`](http://github.com/eggjs/egg/commit/9007b5847e67b678f6624da4610b6bdff9457c52)] - chore: update package.json for release (#2244) (Haoliang Gao <>) +- [[`406142758`](http://github.com/eggjs/egg/commit/40614275845f49512e80d1c8c00d1997ee91b113)] - chore: improve d.ts with ts support (#2306) (Axes <>) +- [[`7fba689b7`](http://github.com/eggjs/egg/commit/7fba689b73fa46fdf7447844338a7f538ad78665)] - docs(controller): session example bug (#2313) (Suyi <>) +- [[`e0e7ed146`](http://github.com/eggjs/egg/commit/e0e7ed146adfe932558628b815caa2d8c64d6939)] - chore(typings): change export interface to class definition (#2293) (waiting <>) +- [[`161107929`](http://github.com/eggjs/egg/commit/1611079291ddcf8cc82dba40a2406dcad20b75b5)] - docs(plugin): add config notice for `addSingleton` function (#2305) (Shangbin Yang <>) +- [[`1c74a8491`](http://github.com/eggjs/egg/commit/1c74a84918869ec035c5767884501a87cce945d5)] - docs: add assets document (#2220) (Haoliang Gao <>) +- [[`e4531e563`](http://github.com/eggjs/egg/commit/e4531e563214472e54b4c467e0d2879e6390cb52)] - docs: EN translation for view plugin dev doc (#2240) (Cemre Mengu <>) +- [[`348ff18d8`](http://github.com/eggjs/egg/commit/348ff18d82e357d9bceba5136c339ef7dfb44bda)] - docs: EN translation for style guide doc (#2239) (Cemre Mengu <>) +- [[`d9c4ec2bb`](http://github.com/eggjs/egg/commit/d9c4ec2bbb3aa29ddcba2efceec6edfa879267d7)] - EN translation for resources doc (#2238) (Cemre Mengu <>) +- [[`46217a5d2`](http://github.com/eggjs/egg/commit/46217a5d2e451433ec86614cfb65336300a074d9)] - docs(security): add ssrf in security (#2274) (Yiyu He <>) +- [[`c3586eab5`](http://github.com/eggjs/egg/commit/c3586eab535ee540ffac664f0311c656ef7adca2)] - docs: deprecate ignoreJSON (#2270) (Yiyu He <>) +- [[`a86334c59`](http://github.com/eggjs/egg/commit/a86334c595530c5f4e9cf65204a4591dfd26bcf0)] - docs: example for custom id when mysql update (#2165) (OnedayLiu <>) +- [[`10327e185`](http://github.com/eggjs/egg/commit/10327e185015098c9c29747abbaf79a352f975d7)] - docs: EN translation for socketio tutorial doc (#2167) (Cemre Mengu <>) +- [[`5b059db6a`](http://github.com/eggjs/egg/commit/5b059db6a879abb3ffe7b30e95855afc8a660107)] - docs: add boilerplate type desc (#2250) (QiChang Li <>) +- [[`9007b5847`](http://github.com/eggjs/egg/commit/9007b5847e67b678f6624da4610b6bdff9457c52)] - chore: update package.json for release (#2244) (Haoliang Gao <>) ## 2018-03-20, Version 2.5.0 @atian25 ### Notable changes -* **feature** - * display router when log app (#2230) - * update `favicon.png` - * upgrade cluster-client to 2.x (#2236) +- **feature** + - display router when log app (#2230) + - update `favicon.png` + - upgrade cluster-client to 2.x (#2236) -* **docs** - * improve d.ts - * add socket.io webchat description (#2198) +- **docs** + - improve d.ts + - add socket.io webchat description (#2198) ### Commits - * [[`6040d6f8f`](http://github.com/eggjs/egg/commit/6040d6f8f1a67282ff697c6d86945bc0cb487fe6)] - chore: fix spelling error rotator (#2242) (HE ZIQIANG <>) - * [[`1554da57e`](http://github.com/eggjs/egg/commit/1554da57ef9d8b0fd2cb023a0cc68b50bee6b69f)] - chore: upgrade cluster-client to 2.x (#2236) (zōng yǔ <>) - * [[`9faa052bf`](http://github.com/eggjs/egg/commit/9faa052bfdffe887c1557126a73a62fe2e462dc5)] - feat: tsd add init module (#2233) (Eward Song <>) - * [[`d5f9059f1`](http://github.com/eggjs/egg/commit/d5f9059f1935a67748033143081755811664df9d)] - docs: translation for basic plugin (#2166) (Cemre Mengu <>) - * [[`7afc7e24b`](http://github.com/eggjs/egg/commit/7afc7e24b60776a71702ae5495d637b1ac4a3d06)] - feat: display router when log app (#2230) (Kiho · Cham <>) - * [[`5e99fd6fd`](http://github.com/eggjs/egg/commit/5e99fd6fd86be4de5a2eca24bc2025f120cef6aa)] - docs: egg-passsport-local -> egg-passport-local (楊傑文 Chuck Yang <>) - * [[`c042366df`](http://github.com/eggjs/egg/commit/c042366df6a691e56c528f16083516a53e114944)] - docs(socket.io): add webchat description (#2198) (TZ | 天猪 <>) - * [[`5cce8795a`](http://github.com/eggjs/egg/commit/5cce8795a733c9096de6e050fec5a87be99b0002)] - chore: fix typo. (#2172) (薛定谔的猫 <>) +- [[`6040d6f8f`](http://github.com/eggjs/egg/commit/6040d6f8f1a67282ff697c6d86945bc0cb487fe6)] - chore: fix spelling error rotator (#2242) (HE ZIQIANG <>) +- [[`1554da57e`](http://github.com/eggjs/egg/commit/1554da57ef9d8b0fd2cb023a0cc68b50bee6b69f)] - chore: upgrade cluster-client to 2.x (#2236) (zōng yǔ <>) +- [[`9faa052bf`](http://github.com/eggjs/egg/commit/9faa052bfdffe887c1557126a73a62fe2e462dc5)] - feat: tsd add init module (#2233) (Eward Song <>) +- [[`d5f9059f1`](http://github.com/eggjs/egg/commit/d5f9059f1935a67748033143081755811664df9d)] - docs: translation for basic plugin (#2166) (Cemre Mengu <>) +- [[`7afc7e24b`](http://github.com/eggjs/egg/commit/7afc7e24b60776a71702ae5495d637b1ac4a3d06)] - feat: display router when log app (#2230) (Kiho · Cham <>) +- [[`5e99fd6fd`](http://github.com/eggjs/egg/commit/5e99fd6fd86be4de5a2eca24bc2025f120cef6aa)] - docs: egg-passsport-local -> egg-passport-local (楊傑文 Chuck Yang <>) +- [[`c042366df`](http://github.com/eggjs/egg/commit/c042366df6a691e56c528f16083516a53e114944)] - docs(socket.io): add webchat description (#2198) (TZ | 天猪 <>) +- [[`5cce8795a`](http://github.com/eggjs/egg/commit/5cce8795a733c9096de6e050fec5a87be99b0002)] - chore: fix typo. (#2172) (薛定谔的猫 <>) ## 2018-03-05, Version 2.4.1 @dead-horse ### Notable changes -* **fix** - * [security] don't allow x-forwarded-host header by default - * `ctx.runInBackground` will try to use custom function name first +- **fix** + - [security] don't allow x-forwarded-host header by default + - `ctx.runInBackground` will try to use custom function name first -* **docs** - * improve d.ts - * add regexp as type of path in Router - * fix type of `render` - * more semantic and moment installation in quickstart +- **docs** + - improve d.ts + - add regexp as type of path in Router + - fix type of `render` + - more semantic and moment installation in quickstart ### Commits - * [[`0eabce6`](http://github.com/eggjs/egg/commit/0eabce6389190cecc00011512ec7e4e63fd0471e)] - fix: don't allow x-forwarded-host header (#2163) (Haoliang Gao <>) - * [[`f0edf96`](http://github.com/eggjs/egg/commit/f0edf9622b6a18831f285e6ceb5a0e2b25b04fd0)] - fix: try to use custom function name first (#2161) (fengmk2 <>) - * [[`1a73720`](http://github.com/eggjs/egg/commit/1a73720d8ba14c612cc6fd38d419212e032049f8)] - fix(typings): add regexp as type of path (#2157) (AngrySean <>) - * [[`b55e908`](http://github.com/eggjs/egg/commit/b55e908643dc2ef1a21c7a4b11559e1785985792)] - doc(quickstart): more semantic and moment installation (#2154) (Kiho · Cham <>) - * [[`951e236`](http://github.com/eggjs/egg/commit/951e236586f3fdc988504f4138351b2c7778e67c)] - Fix type of `render` (#2155) (Arniu Tseng <>) +- [[`0eabce6`](http://github.com/eggjs/egg/commit/0eabce6389190cecc00011512ec7e4e63fd0471e)] - fix: don't allow x-forwarded-host header (#2163) (Haoliang Gao <>) +- [[`f0edf96`](http://github.com/eggjs/egg/commit/f0edf9622b6a18831f285e6ceb5a0e2b25b04fd0)] - fix: try to use custom function name first (#2161) (fengmk2 <>) +- [[`1a73720`](http://github.com/eggjs/egg/commit/1a73720d8ba14c612cc6fd38d419212e032049f8)] - fix(typings): add regexp as type of path (#2157) (AngrySean <>) +- [[`b55e908`](http://github.com/eggjs/egg/commit/b55e908643dc2ef1a21c7a4b11559e1785985792)] - doc(quickstart): more semantic and moment installation (#2154) (Kiho · Cham <>) +- [[`951e236`](http://github.com/eggjs/egg/commit/951e236586f3fdc988504f4138351b2c7778e67c)] - Fix type of `render` (#2155) (Arniu Tseng <>) ## 2018-02-28, Version 2.4.0, @fengmk2 ### Notable changes -* **feature** - * support Keep-Alive Header - -* **fix** - * add logger in base_context_class - -* **docs** - * Lots of d.ts improved. - * add context - * add urllib - * add resources & logger - * new documents - * how to call the service - * socket.io tutorial - * add events on application - -### Commits - - * [[`79927324a`](http://github.com/eggjs/egg/commit/79927324a5aeb1f826fc9f133bed253d8324c62e)] - fix: add logger in base_context_class (#2149) (Axes <>) - * [[`a73900231`](http://github.com/eggjs/egg/commit/a7390023150ff4d5a7ec069276a94542a7ef67fa)] - feat: support Keep-Alive Header (#2146) (fengmk2 <>) - * [[`c8284367c`](http://github.com/eggjs/egg/commit/c8284367c727aa2da453a1a485c4d7f97cfb3967)] - docs(ts): fix some d.ts (#2144) (TZ | 天猪 <>) - * [[`e0282b923`](http://github.com/eggjs/egg/commit/e0282b923375132fcc3b936b471999a84eb1e941)] - docs(router): add definition of ctx (#2136) (重庆 <<1756260160@qq.com>>) - * [[`3e7ef6aa5`](http://github.com/eggjs/egg/commit/3e7ef6aa566d800411822d9a4195c9df34634789)] - docs(app-start): how to call service (#2133) (TZ | 天猪 <>) - * [[`9472b5828`](http://github.com/eggjs/egg/commit/9472b5828c95cd1dec2910b657d1e6c34372a6a2)] - docs(schedule): fix log dir (#2123) (TZ | 天猪 <>) - * [[`ede433fc5`](http://github.com/eggjs/egg/commit/ede433fc594c915683a519bf9b409209812806cf)] - docs(unittest):fix some mistakes (#2110) (恬竹 <<2632807692@qq.com>>) - * [[`2d03c79a1`](http://github.com/eggjs/egg/commit/2d03c79a1842846c4caf2f3b971a5bae5fc9f24d)] - chore: add urllib declaration support in index.d.ts (#2117) (SoraYama <>) - * [[`fd6fa2495`](http://github.com/eggjs/egg/commit/fd6fa24955a7a7bceaad7b2f754123282b7e1cbe)] - docs(2.x-advanced-plugin):fix some descriptions (#2111) (恬竹 <<2632807692@qq.com>>) - * [[`0a208d741`](http://github.com/eggjs/egg/commit/0a208d7413d77f12048df91b6bdb6e2dfd047c89)] - docs: translation for advanced/plugin.md (#2075) (DukeFightLife <>) - * [[`42e4ea4c1`](http://github.com/eggjs/egg/commit/42e4ea4c12a542671bac7ca92931e83d0fc439f4)] - docs(schedule):fix some places (#2105) (恬竹 <<2632807692@qq.com>>) - * [[`63278c229`](http://github.com/eggjs/egg/commit/63278c2293b0899165386288c38cac44aa7a0b71)] - docs(2.x-basic-extend):fix some mistakes (#2107) (恬竹 <<2632807692@qq.com>>) - * [[`7a604d37f`](http://github.com/eggjs/egg/commit/7a604d37f5184c268263779fa2b8ca459e3d6f5b)] - docs(2.x-basic-service):fix some mistakes of service (#2102) (恬竹 <<2632807692@qq.com>>) - * [[`a1a4e7dd3`](http://github.com/eggjs/egg/commit/a1a4e7dd32bf040b69e8c8bfbdcae3e483eee335)] - docs(plugin): add description for plugin.local.js (#2104) (TZ | 天猪 <>) - * [[`2cdfcc249`](http://github.com/eggjs/egg/commit/2cdfcc249863630dbb298374dbbe2b45864a0e1c)] - docs(development): adjust to new version vscode (#2098) (TZ | 天猪 <>) - * [[`bb4b29002`](http://github.com/eggjs/egg/commit/bb4b290027a6dcf8404ae357e29aaa6a76d5413a)] - docs(faq): add the most common mistake of config (#2086) (TZ | 天猪 <>) - * [[`5621a8574`](http://github.com/eggjs/egg/commit/5621a8574b60d61dab79f601105b69710559831c)] - docs(schedule): logging && args (#2091) (TZ | 天猪 <>) - * [[`03a894439`](http://github.com/eggjs/egg/commit/03a89443904211785ca600ec74f78d75bbf7a299)] - docs: d.ts of resources& logger (#2079) (x22x22 <>) - * [[`bbfacc5a7`](http://github.com/eggjs/egg/commit/bbfacc5a75984a7ddc111195b51d7da8bd6d0713)] - docs(middleware): use app.middleware instead of app.middlewares (#2077) (x22x22 <>) - * [[`7e9f330ee`](http://github.com/eggjs/egg/commit/7e9f330eea2efcc26e99eb89ad3fb40c517e0101)] - docs(socket.io): add tutorial (#1913) (Suyi <>) - * [[`1224dd65f`](http://github.com/eggjs/egg/commit/1224dd65f2e4dadcce70d9a6e8e66122d93fbdd7)] - docs(2.x-basic-controller):fix some descriptions of basic-controller (#2043) (恬竹 <<2632807692@qq.com>>) - * [[`fa5bdaeb5`](http://github.com/eggjs/egg/commit/fa5bdaeb5fec6385f81bc4c3781036df3fa6d870)] - style(app/extend/request.js): Some Comments from Chinese To English in union (#2051) (DongWei <>) - * [[`06e7710c7`](http://github.com/eggjs/egg/commit/06e7710c73c5f4ad313d08b770e5874919e21b88)] - docs: add events on application (#2039) (Yiyu He <>) - * [[`65e038132`](http://github.com/eggjs/egg/commit/65e038132c9183c66c11fb50e3a8bc6358cdae4c)] - docs(advanced/loader): translate (#1654) (Weilun Xiong <>) +- **feature** + - support Keep-Alive Header + +- **fix** + - add logger in base_context_class + +- **docs** + - Lots of d.ts improved. + - add context + - add urllib + - add resources & logger + - new documents + - how to call the service + - socket.io tutorial + - add events on application + +### Commits + +- [[`79927324a`](http://github.com/eggjs/egg/commit/79927324a5aeb1f826fc9f133bed253d8324c62e)] - fix: add logger in base_context_class (#2149) (Axes <>) +- [[`a73900231`](http://github.com/eggjs/egg/commit/a7390023150ff4d5a7ec069276a94542a7ef67fa)] - feat: support Keep-Alive Header (#2146) (fengmk2 <>) +- [[`c8284367c`](http://github.com/eggjs/egg/commit/c8284367c727aa2da453a1a485c4d7f97cfb3967)] - docs(ts): fix some d.ts (#2144) (TZ | 天猪 <>) +- [[`e0282b923`](http://github.com/eggjs/egg/commit/e0282b923375132fcc3b936b471999a84eb1e941)] - docs(router): add definition of ctx (#2136) (重庆 <<1756260160@qq.com>>) +- [[`3e7ef6aa5`](http://github.com/eggjs/egg/commit/3e7ef6aa566d800411822d9a4195c9df34634789)] - docs(app-start): how to call service (#2133) (TZ | 天猪 <>) +- [[`9472b5828`](http://github.com/eggjs/egg/commit/9472b5828c95cd1dec2910b657d1e6c34372a6a2)] - docs(schedule): fix log dir (#2123) (TZ | 天猪 <>) +- [[`ede433fc5`](http://github.com/eggjs/egg/commit/ede433fc594c915683a519bf9b409209812806cf)] - docs(unittest):fix some mistakes (#2110) (恬竹 <<2632807692@qq.com>>) +- [[`2d03c79a1`](http://github.com/eggjs/egg/commit/2d03c79a1842846c4caf2f3b971a5bae5fc9f24d)] - chore: add urllib declaration support in index.d.ts (#2117) (SoraYama <>) +- [[`fd6fa2495`](http://github.com/eggjs/egg/commit/fd6fa24955a7a7bceaad7b2f754123282b7e1cbe)] - docs(2.x-advanced-plugin):fix some descriptions (#2111) (恬竹 <<2632807692@qq.com>>) +- [[`0a208d741`](http://github.com/eggjs/egg/commit/0a208d7413d77f12048df91b6bdb6e2dfd047c89)] - docs: translation for advanced/plugin.md (#2075) (DukeFightLife <>) +- [[`42e4ea4c1`](http://github.com/eggjs/egg/commit/42e4ea4c12a542671bac7ca92931e83d0fc439f4)] - docs(schedule):fix some places (#2105) (恬竹 <<2632807692@qq.com>>) +- [[`63278c229`](http://github.com/eggjs/egg/commit/63278c2293b0899165386288c38cac44aa7a0b71)] - docs(2.x-basic-extend):fix some mistakes (#2107) (恬竹 <<2632807692@qq.com>>) +- [[`7a604d37f`](http://github.com/eggjs/egg/commit/7a604d37f5184c268263779fa2b8ca459e3d6f5b)] - docs(2.x-basic-service):fix some mistakes of service (#2102) (恬竹 <<2632807692@qq.com>>) +- [[`a1a4e7dd3`](http://github.com/eggjs/egg/commit/a1a4e7dd32bf040b69e8c8bfbdcae3e483eee335)] - docs(plugin): add description for plugin.local.js (#2104) (TZ | 天猪 <>) +- [[`2cdfcc249`](http://github.com/eggjs/egg/commit/2cdfcc249863630dbb298374dbbe2b45864a0e1c)] - docs(development): adjust to new version vscode (#2098) (TZ | 天猪 <>) +- [[`bb4b29002`](http://github.com/eggjs/egg/commit/bb4b290027a6dcf8404ae357e29aaa6a76d5413a)] - docs(faq): add the most common mistake of config (#2086) (TZ | 天猪 <>) +- [[`5621a8574`](http://github.com/eggjs/egg/commit/5621a8574b60d61dab79f601105b69710559831c)] - docs(schedule): logging && args (#2091) (TZ | 天猪 <>) +- [[`03a894439`](http://github.com/eggjs/egg/commit/03a89443904211785ca600ec74f78d75bbf7a299)] - docs: d.ts of resources& logger (#2079) (x22x22 <>) +- [[`bbfacc5a7`](http://github.com/eggjs/egg/commit/bbfacc5a75984a7ddc111195b51d7da8bd6d0713)] - docs(middleware): use app.middleware instead of app.middlewares (#2077) (x22x22 <>) +- [[`7e9f330ee`](http://github.com/eggjs/egg/commit/7e9f330eea2efcc26e99eb89ad3fb40c517e0101)] - docs(socket.io): add tutorial (#1913) (Suyi <>) +- [[`1224dd65f`](http://github.com/eggjs/egg/commit/1224dd65f2e4dadcce70d9a6e8e66122d93fbdd7)] - docs(2.x-basic-controller):fix some descriptions of basic-controller (#2043) (恬竹 <<2632807692@qq.com>>) +- [[`fa5bdaeb5`](http://github.com/eggjs/egg/commit/fa5bdaeb5fec6385f81bc4c3781036df3fa6d870)] - style(app/extend/request.js): Some Comments from Chinese To English in union (#2051) (DongWei <>) +- [[`06e7710c7`](http://github.com/eggjs/egg/commit/06e7710c73c5f4ad313d08b770e5874919e21b88)] - docs: add events on application (#2039) (Yiyu He <>) +- [[`65e038132`](http://github.com/eggjs/egg/commit/65e038132c9183c66c11fb50e3a8bc6358cdae4c)] - docs(advanced/loader): translate (#1654) (Weilun Xiong <>) ## 2018-01-26, Version 2.3.0, @dead-horse ### Notable changes -* **feature** - * emit `request` and `response` event in every request +- **feature** + - emit `request` and `response` event in every request -* **docs** - * improve english docs - * add alinode usage +- **docs** + - improve english docs + - add alinode usage ### Commits - * [[`50a0f8a`](http://github.com/eggjs/egg/commit/50a0f8ac8fe246d664f73f171b8886f9b9c2eda7)] - doc: fix deploy example (dead-horse <>) - * [[`3b7a313`](http://github.com/eggjs/egg/commit/3b7a313965f9c8ae6e20a16dd74533b1885f216f)] - docs(deploy): more about alinode (#2036) (TZ | 天猪 <>) - * [[`950b9e6`](http://github.com/eggjs/egg/commit/950b9e684f2441674ed85a3c0152002991d2ff86)] - doc: fix deploy docs (dead-horse <>) - * [[`18d6436`](http://github.com/eggjs/egg/commit/18d6436195ca1a73098c643d39ce4560b20e7d76)] - docs: translate advanced/cluster-client.md (#1839) (学究 <>) - * [[`287c761`](http://github.com/eggjs/egg/commit/287c7615ad425b130e2c669a41409bfa763feef2)] - Update deployment.md (#1979) (juju <>) - * [[`22dfaa7`](http://github.com/eggjs/egg/commit/22dfaa72e3851196153f4ecb7f3599d2951e9b1b)] - feat: emit request and response event (#2020) (Yiyu He <>) - * [[`ddbb4b3`](http://github.com/eggjs/egg/commit/ddbb4b3c0ec7cfc5c9b1baa7e678770613bd4761)] - docs(deploy): add alinode (#2025) (TZ | 天猪 <>) - * [[`b5d823f`](http://github.com/eggjs/egg/commit/b5d823f52a770f879da46c6968adadd3fa14e8d7)] - docs(core/unittest): fix path of helper.js(#2029) (#2030) (Jiulong Hu <>) - * [[`1e3a4b3`](http://github.com/eggjs/egg/commit/1e3a4b35801e136dd4f1fbaf3c49b771a50c0f72)] - docs(basic-router):fix some places of basic-router (#2012) (恬竹 <<2632807692@qq.com>>) +- [[`50a0f8a`](http://github.com/eggjs/egg/commit/50a0f8ac8fe246d664f73f171b8886f9b9c2eda7)] - doc: fix deploy example (dead-horse <>) +- [[`3b7a313`](http://github.com/eggjs/egg/commit/3b7a313965f9c8ae6e20a16dd74533b1885f216f)] - docs(deploy): more about alinode (#2036) (TZ | 天猪 <>) +- [[`950b9e6`](http://github.com/eggjs/egg/commit/950b9e684f2441674ed85a3c0152002991d2ff86)] - doc: fix deploy docs (dead-horse <>) +- [[`18d6436`](http://github.com/eggjs/egg/commit/18d6436195ca1a73098c643d39ce4560b20e7d76)] - docs: translate advanced/cluster-client.md (#1839) (学究 <>) +- [[`287c761`](http://github.com/eggjs/egg/commit/287c7615ad425b130e2c669a41409bfa763feef2)] - Update deployment.md (#1979) (juju <>) +- [[`22dfaa7`](http://github.com/eggjs/egg/commit/22dfaa72e3851196153f4ecb7f3599d2951e9b1b)] - feat: emit request and response event (#2020) (Yiyu He <>) +- [[`ddbb4b3`](http://github.com/eggjs/egg/commit/ddbb4b3c0ec7cfc5c9b1baa7e678770613bd4761)] - docs(deploy): add alinode (#2025) (TZ | 天猪 <>) +- [[`b5d823f`](http://github.com/eggjs/egg/commit/b5d823f52a770f879da46c6968adadd3fa14e8d7)] - docs(core/unittest): fix path of helper.js(#2029) (#2030) (Jiulong Hu <>) +- [[`1e3a4b3`](http://github.com/eggjs/egg/commit/1e3a4b35801e136dd4f1fbaf3c49b771a50c0f72)] - docs(basic-router):fix some places of basic-router (#2012) (恬竹 <<2632807692@qq.com>>) ## 2018-01-22, Version 2.2.1, @dead-horse ### Notable changes -* **fix** - * log cookie's key when cookie exceed limit length - -* **document** - * improve english documents, fix some grammars - * add link to alicloud node.js perfomance platform - * use PATCH method in resource router - -### Commits - - * [[`aa46eb2`](http://github.com/eggjs/egg/commit/aa46eb26d45012036c69c524db512ed16fde7b6b)] - fix: log cookie's key when cookie exceed limit length (#1996) (Yiyu He <>) - * [[`7993b45`](http://github.com/eggjs/egg/commit/7993b45ec2af8c2d96d82370d877476786504dc8)] - docs(basic-middleware):fix some descriptions of basic-middleware (#1998) (恬竹 <<2632807692@qq.com>>) - * [[`b2d09e1`](http://github.com/eggjs/egg/commit/b2d09e150da70a08c1886b00031c0f07eeb7d830)] - docs: put => patch. (#1793) (#1938) (吴建金 <>) - * [[`dede240`](http://github.com/eggjs/egg/commit/dede240340570c00e3baed8098853a44c902dc21)] - feat: add helper interface in d.ts (#1989) (Axes <>) - * [[`19fe608`](http://github.com/eggjs/egg/commit/19fe6085fedabfc09eb9c26534df237decf4d28e)] - docs: add deer stat (#1974) (TZ | 天猪 <>) - * [[`cef371e`](http://github.com/eggjs/egg/commit/cef371e4a176c62d9b44c0f1e55668e992921d2d)] - docs(basic-env): fix some descriptions base on the Chinese version (#1930) (恬竹 <<2632807692@qq.com>>) - * [[`55d08bd`](http://github.com/eggjs/egg/commit/55d08bded812b81efeee96a0e3465728c7f4f5a2)] - fix(ts): error declare of route.resource (#1959) (AntSworD <>) - * [[`32d7c81`](http://github.com/eggjs/egg/commit/32d7c8199611b00cd5117e6adcf8904ea0b33ff5)] - docs: fix word error (#1965) (jxDeveloper <<896222652@qq.com>>) - * [[`3acf45f`](http://github.com/eggjs/egg/commit/3acf45f77ef791b1e6467bd4047511d867d46cc9)] - docs(basic-config): fix some word spelling (#1931) (恬竹 <<2632807692@qq.com>>) - * [[`0e90819`](http://github.com/eggjs/egg/commit/0e9081954a765228ee9d590f01f3bfaaf1a4e5d8)] - docs(advanced/framework): translation (#1668) (freebyron <>) - * [[`ab1b08e`](http://github.com/eggjs/egg/commit/ab1b08ef520ab8db4cddd8f6cf52f1aa87d6975f)] - docs: fix en index (#1915) (Weilun Xiong <>) - * [[`2270f7f`](http://github.com/eggjs/egg/commit/2270f7f0417f9c78958c6b51e70ad7a0d838d6ec)] - docs(basic-objects): fix some descriptions (#1903) (恬竹 <<2632807692@qq.com>>) - * [[`c136470`](http://github.com/eggjs/egg/commit/c136470861b35a5f796d4edcdd8f6fbce41f7314)] - test: use Buffer.alloc, Buffer.from. (#1895) (薛定谔的猫 <>) - * [[`73bc636`](http://github.com/eggjs/egg/commit/73bc636ddb82bd73fa14fb5f56e8ffe6260b46cc)] - docs(links): Add link to alicloud node.js perfomance platform (#1894) (Jackson Tian <>) - * [[`55d1b0e`](http://github.com/eggjs/egg/commit/55d1b0eb5c4ca27668559b94259f0670b60d57b6)] - docs(deploy): add --ignore-stderr (#1876) (TZ | 天猪 <>) - * [[`532110a`](http://github.com/eggjs/egg/commit/532110abbc01cf3f225c47ed6219d9434c48808c)] - fix: fix 404 page url (#1881) (sam <<289623783@qq.com>>) +- **fix** + - log cookie's key when cookie exceed limit length + +- **document** + - improve english documents, fix some grammars + - add link to alicloud node.js perfomance platform + - use PATCH method in resource router + +### Commits + +- [[`aa46eb2`](http://github.com/eggjs/egg/commit/aa46eb26d45012036c69c524db512ed16fde7b6b)] - fix: log cookie's key when cookie exceed limit length (#1996) (Yiyu He <>) +- [[`7993b45`](http://github.com/eggjs/egg/commit/7993b45ec2af8c2d96d82370d877476786504dc8)] - docs(basic-middleware):fix some descriptions of basic-middleware (#1998) (恬竹 <<2632807692@qq.com>>) +- [[`b2d09e1`](http://github.com/eggjs/egg/commit/b2d09e150da70a08c1886b00031c0f07eeb7d830)] - docs: put => patch. (#1793) (#1938) (吴建金 <>) +- [[`dede240`](http://github.com/eggjs/egg/commit/dede240340570c00e3baed8098853a44c902dc21)] - feat: add helper interface in d.ts (#1989) (Axes <>) +- [[`19fe608`](http://github.com/eggjs/egg/commit/19fe6085fedabfc09eb9c26534df237decf4d28e)] - docs: add deer stat (#1974) (TZ | 天猪 <>) +- [[`cef371e`](http://github.com/eggjs/egg/commit/cef371e4a176c62d9b44c0f1e55668e992921d2d)] - docs(basic-env): fix some descriptions base on the Chinese version (#1930) (恬竹 <<2632807692@qq.com>>) +- [[`55d08bd`](http://github.com/eggjs/egg/commit/55d08bded812b81efeee96a0e3465728c7f4f5a2)] - fix(ts): error declare of route.resource (#1959) (AntSworD <>) +- [[`32d7c81`](http://github.com/eggjs/egg/commit/32d7c8199611b00cd5117e6adcf8904ea0b33ff5)] - docs: fix word error (#1965) (jxDeveloper <<896222652@qq.com>>) +- [[`3acf45f`](http://github.com/eggjs/egg/commit/3acf45f77ef791b1e6467bd4047511d867d46cc9)] - docs(basic-config): fix some word spelling (#1931) (恬竹 <<2632807692@qq.com>>) +- [[`0e90819`](http://github.com/eggjs/egg/commit/0e9081954a765228ee9d590f01f3bfaaf1a4e5d8)] - docs(advanced/framework): translation (#1668) (freebyron <>) +- [[`ab1b08e`](http://github.com/eggjs/egg/commit/ab1b08ef520ab8db4cddd8f6cf52f1aa87d6975f)] - docs: fix en index (#1915) (Weilun Xiong <>) +- [[`2270f7f`](http://github.com/eggjs/egg/commit/2270f7f0417f9c78958c6b51e70ad7a0d838d6ec)] - docs(basic-objects): fix some descriptions (#1903) (恬竹 <<2632807692@qq.com>>) +- [[`c136470`](http://github.com/eggjs/egg/commit/c136470861b35a5f796d4edcdd8f6fbce41f7314)] - test: use Buffer.alloc, Buffer.from. (#1895) (薛定谔的猫 <>) +- [[`73bc636`](http://github.com/eggjs/egg/commit/73bc636ddb82bd73fa14fb5f56e8ffe6260b46cc)] - docs(links): Add link to alicloud node.js perfomance platform (#1894) (Jackson Tian <>) +- [[`55d1b0e`](http://github.com/eggjs/egg/commit/55d1b0eb5c4ca27668559b94259f0670b60d57b6)] - docs(deploy): add --ignore-stderr (#1876) (TZ | 天猪 <>) +- [[`532110a`](http://github.com/eggjs/egg/commit/532110abbc01cf3f225c47ed6219d9434c48808c)] - fix: fix 404 page url (#1881) (sam <<289623783@qq.com>>) ## 2017-12-26, Version 2.2.0, @dead-horse ### Notable changes -* **feature** - * `config.meta.logging` to enable log every request when received +- **feature** + - `config.meta.logging` to enable log every request when received -* **document** - * fix some grammars - * add rule for issue +- **document** + - fix some grammars + - add rule for issue ### Commits -* [[`9fe5b85`](http://github.com/eggjs/egg/commit/9fe5b8563958d313b02482e5b3fe69c342acfa71)] - feat: enable request started log on meta middleware (#1877) (fengmk2 <>) -* [[`8ce9611`](http://github.com/eggjs/egg/commit/8ce9611e2e2e5098a7a4557e0f8d29cd93ab468c)] - docs(objects): fix some grammars (#1806) (恬竹 <<2632807692@qq.com>>) -* [[`e43aa2b`](http://github.com/eggjs/egg/commit/e43aa2bad227475744ef6422f376475d0ee266c4)] - docs(error-handling): fix some words (#1874) (Fan <>) -* [[`4c1617a`](http://github.com/eggjs/egg/commit/4c1617a16ee3df1b455f5eeb1cb31e37e5f593c1)] - docs(faq): add rule for issue (#1861) (TZ | 天猪 <>) +- [[`9fe5b85`](http://github.com/eggjs/egg/commit/9fe5b8563958d313b02482e5b3fe69c342acfa71)] - feat: enable request started log on meta middleware (#1877) (fengmk2 <>) +- [[`8ce9611`](http://github.com/eggjs/egg/commit/8ce9611e2e2e5098a7a4557e0f8d29cd93ab468c)] - docs(objects): fix some grammars (#1806) (恬竹 <<2632807692@qq.com>>) +- [[`e43aa2b`](http://github.com/eggjs/egg/commit/e43aa2bad227475744ef6422f376475d0ee266c4)] - docs(error-handling): fix some words (#1874) (Fan <>) +- [[`4c1617a`](http://github.com/eggjs/egg/commit/4c1617a16ee3df1b455f5eeb1cb31e37e5f593c1)] - docs(faq): add rule for issue (#1861) (TZ | 天猪 <>) ## 2017-12-15, Version 2.1.0, @dead-horse ### Notable changes -* **feature** - * add 400 response for broken client request to instead of empty response - * dump application router json - -* **fix** - * fix: run dumpConfig at the last ready callback - -* **document** - * migrate docs to egg 2 - * add document for passport - -### Commits - -* [[`40df153`](http://github.com/eggjs/egg/commit/40df153dd7ca8124a7502ba6cdc838835388a0ae)] - feat: add 400 response for broken client request to instead of empty response (#1829) (Khaidi Chu <>) -* [[`d0ee9f2`](http://github.com/eggjs/egg/commit/d0ee9f2500e69a1e0662c9ea597bf97db3418041)] - docs(passport): fix some description (#1828) (TZ | 天猪 <>) -* [[`f7c6a0a`](http://github.com/eggjs/egg/commit/f7c6a0a835ea950e98e40a0b4b83736912b5ab82)] - docs(passport): add description (#1825) (TZ | 天猪 <>) -* [[`f66d9be`](http://github.com/eggjs/egg/commit/f66d9be57807c04058511b47611afa890884b2a5)] - docs(passport): the missing docs for passport (#1824) (TZ | 天猪 <>) -* [[`18f93f0`](http://github.com/eggjs/egg/commit/18f93f0b927a08e6bd356f9fcc6a3141e813e85f)] - docs(core/view.md): translation (#1577) (Zhongyuan <>) -* [[`7e05669`](http://github.com/eggjs/egg/commit/7e056692506f5801390fd804d75bf6756991a54b)] - 1. docs(error-handle): missing function keywords. (#1819) (M.Y.Akashi <>) -* [[`89e114c`](http://github.com/eggjs/egg/commit/89e114cb88ef1ef96e479001bf0f8250867111c9)] - docs: add AntV links (#1809) (TZ | 天猪 <>) -* [[`bdfd3cc`](http://github.com/eggjs/egg/commit/bdfd3cc62b8377cadac2a6c108944d86eaca3df0)] - docs(router): new style & remove app.verb (#1803) (TZ | 天猪 <>) -* [[`4c9eacb`](http://github.com/eggjs/egg/commit/4c9eacbb7d4560924602103e5e23ae578ac34a52)] - docs(middleware): add description of import koa middleware (#1805) (TZ | 天猪 <>) -* [[`c152dee`](http://github.com/eggjs/egg/commit/c152deec69c3dbb06ce87433a46bab0bc61e295b)] - docs(loader): adjust extends way (#1729) (TZ | 天猪 <>) -* [[`289f8cd`](http://github.com/eggjs/egg/commit/289f8cd3d90cc24c55fa51e3d75f5750233af7ee)] - docs(progressive):changes some grammar (#1773) (恬竹 <<2632807692@qq.com>>) -* [[`ae87460`](http://github.com/eggjs/egg/commit/ae87460d6aacb38f4d60d703450f8085c72d3b0d)] - docs(migration): add description for plugin breakchange (#1766) (TZ | 天猪 <>) -* [[`a2788a8`](http://github.com/eggjs/egg/commit/a2788a870175d6c1abdad3c379bbb9adc6c24ba9)] - docs(controller): import base controller directly (#1771) (Yiyu He <>) -* [[`7ebfc9b`](http://github.com/eggjs/egg/commit/7ebfc9b96b03a6b1bdffc3da65c6940902dc3086)] - docs(quickstart): fix typo in code example (#1765) (Darren Poon <>) -* [[`6ff6998`](http://github.com/eggjs/egg/commit/6ff699824dce6962d7aa9e9e48f41a50a994834f)] - docs: add security english translation (#1691) (Adams <>) -* [[`a061f21`](http://github.com/eggjs/egg/commit/a061f21178b2253b587dab780ba74f19605109a4)] - docs(intro): make some changes for egg-and-koa (#1739) (恬竹 <<2632807692@qq.com>>) -* [[`d752b3b`](http://github.com/eggjs/egg/commit/d752b3b795cc0c5a579770695fcadd3db713ff6f)] - docs(deployment): adjust with new version egg-scripts (#1757) (TZ | 天猪 <>) -* [[`1b12b51`](http://github.com/eggjs/egg/commit/1b12b519937e80728d133ea24ff88a2568b72a57)] - docs(cookie-session): use async (#1723) (TZ | 天猪 <>) -* [[`5c88026`](http://github.com/eggjs/egg/commit/5c880266f9968a2e9b102db7c0eea2c7b0f09a43)] - docs(plugin): use async (#1730) (TZ | 天猪 <>) -* [[`ebb8adf`](http://github.com/eggjs/egg/commit/ebb8adfadcf21ba29997c65d5adc5a92235ffa8d)] - some changes of docs(what is egg) (#1734) (恬竹 <<2632807692@qq.com>>) -* [[`2da00fc`](http://github.com/eggjs/egg/commit/2da00fca45d9bc161cae5ab9754a3fcc0321b9c7)] - docs(framework): use new way (#1728) (TZ | 天猪 <>) -* [[`47fbee5`](http://github.com/eggjs/egg/commit/47fbee574b94d9f6420d44e7a8f0ccec035d94f4)] - docs(cluster-client): use async (#1727) (TZ | 天猪 <>) -* [[`1420682`](http://github.com/eggjs/egg/commit/1420682dc5b6fb14342373d9b70614c3de0c015b)] - docs(ipc): use async (#1722) (TZ | 天猪 <>) -* [[`503b69b`](http://github.com/eggjs/egg/commit/503b69b2e5c3f59b9c3c307a50e711cd8eb8d967)] - feat: dump application router json (fengmk2 <>) -* [[`76ff783`](http://github.com/eggjs/egg/commit/76ff783b80a9d9ffc01db1b434c25fedd6e27ca7)] - fix: run dumpConfig at the last ready callback (fengmk2 <>) -* [[`50efe4c`](http://github.com/eggjs/egg/commit/50efe4ceb9a4c8ec902a503db7ad10ffe7819e1a)] - docs(httpclient): use async (#1724) (TZ | 天猪 <>) -* [[`d043148`](http://github.com/eggjs/egg/commit/d043148b8ee69614098b39604dd6b7d7e1a84810)] - docs: remove async-function (#1713) (TZ | 天猪 <>) -* [[`e3ef3ec`](http://github.com/eggjs/egg/commit/e3ef3ec65c5e2874c813f6cda18b61b630d137be)] - docs(restful): use async (#1709) (TZ | 天猪 <>) -* [[`b042937`](http://github.com/eggjs/egg/commit/b042937b1e77b8206206a248c9f3e3ab82b7d6d8)] - docs(error-handling): use async (#1721) (TZ | 天猪 <>) -* [[`80ab243`](http://github.com/eggjs/egg/commit/80ab2439d508e9e0574df31061b5bb14988c2e3e)] - docs(i18n): use async (#1720) (TZ | 天猪 <>) -* [[`6741999`](http://github.com/eggjs/egg/commit/67419996a3abd403ab8d67755ecb98c3a9b97338)] - docs(logger): use async (#1719) (TZ | 天猪 <>) -* [[`f39c105`](http://github.com/eggjs/egg/commit/f39c105067e08fe416f86d0a415f5475ce66ba17)] - docs(view): use async (#1717) (TZ | 天猪 <>) -* [[`cf3de0f`](http://github.com/eggjs/egg/commit/cf3de0f248e3435a7d6ac41ece16dea55f5e86c9)] - docs(unittest): use async (#1716) (TZ | 天猪 <>) -* [[`cb9c9a4`](http://github.com/eggjs/egg/commit/cb9c9a43015a47347273bf8a09d971205b0d57ec)] - docs(mysql): use async (#1711) (TZ | 天猪 <>) +- **feature** + - add 400 response for broken client request to instead of empty response + - dump application router json + +- **fix** + - fix: run dumpConfig at the last ready callback + +- **document** + - migrate docs to egg 2 + - add document for passport + +### Commits + +- [[`40df153`](http://github.com/eggjs/egg/commit/40df153dd7ca8124a7502ba6cdc838835388a0ae)] - feat: add 400 response for broken client request to instead of empty response (#1829) (Khaidi Chu <>) +- [[`d0ee9f2`](http://github.com/eggjs/egg/commit/d0ee9f2500e69a1e0662c9ea597bf97db3418041)] - docs(passport): fix some description (#1828) (TZ | 天猪 <>) +- [[`f7c6a0a`](http://github.com/eggjs/egg/commit/f7c6a0a835ea950e98e40a0b4b83736912b5ab82)] - docs(passport): add description (#1825) (TZ | 天猪 <>) +- [[`f66d9be`](http://github.com/eggjs/egg/commit/f66d9be57807c04058511b47611afa890884b2a5)] - docs(passport): the missing docs for passport (#1824) (TZ | 天猪 <>) +- [[`18f93f0`](http://github.com/eggjs/egg/commit/18f93f0b927a08e6bd356f9fcc6a3141e813e85f)] - docs(core/view.md): translation (#1577) (Zhongyuan <>) +- [[`7e05669`](http://github.com/eggjs/egg/commit/7e056692506f5801390fd804d75bf6756991a54b)] - 1. docs(error-handle): missing function keywords. (#1819) (M.Y.Akashi <>) +- [[`89e114c`](http://github.com/eggjs/egg/commit/89e114cb88ef1ef96e479001bf0f8250867111c9)] - docs: add AntV links (#1809) (TZ | 天猪 <>) +- [[`bdfd3cc`](http://github.com/eggjs/egg/commit/bdfd3cc62b8377cadac2a6c108944d86eaca3df0)] - docs(router): new style & remove app.verb (#1803) (TZ | 天猪 <>) +- [[`4c9eacb`](http://github.com/eggjs/egg/commit/4c9eacbb7d4560924602103e5e23ae578ac34a52)] - docs(middleware): add description of import koa middleware (#1805) (TZ | 天猪 <>) +- [[`c152dee`](http://github.com/eggjs/egg/commit/c152deec69c3dbb06ce87433a46bab0bc61e295b)] - docs(loader): adjust extends way (#1729) (TZ | 天猪 <>) +- [[`289f8cd`](http://github.com/eggjs/egg/commit/289f8cd3d90cc24c55fa51e3d75f5750233af7ee)] - docs(progressive):changes some grammar (#1773) (恬竹 <<2632807692@qq.com>>) +- [[`ae87460`](http://github.com/eggjs/egg/commit/ae87460d6aacb38f4d60d703450f8085c72d3b0d)] - docs(migration): add description for plugin breakchange (#1766) (TZ | 天猪 <>) +- [[`a2788a8`](http://github.com/eggjs/egg/commit/a2788a870175d6c1abdad3c379bbb9adc6c24ba9)] - docs(controller): import base controller directly (#1771) (Yiyu He <>) +- [[`7ebfc9b`](http://github.com/eggjs/egg/commit/7ebfc9b96b03a6b1bdffc3da65c6940902dc3086)] - docs(quickstart): fix typo in code example (#1765) (Darren Poon <>) +- [[`6ff6998`](http://github.com/eggjs/egg/commit/6ff699824dce6962d7aa9e9e48f41a50a994834f)] - docs: add security english translation (#1691) (Adams <>) +- [[`a061f21`](http://github.com/eggjs/egg/commit/a061f21178b2253b587dab780ba74f19605109a4)] - docs(intro): make some changes for egg-and-koa (#1739) (恬竹 <<2632807692@qq.com>>) +- [[`d752b3b`](http://github.com/eggjs/egg/commit/d752b3b795cc0c5a579770695fcadd3db713ff6f)] - docs(deployment): adjust with new version egg-scripts (#1757) (TZ | 天猪 <>) +- [[`1b12b51`](http://github.com/eggjs/egg/commit/1b12b519937e80728d133ea24ff88a2568b72a57)] - docs(cookie-session): use async (#1723) (TZ | 天猪 <>) +- [[`5c88026`](http://github.com/eggjs/egg/commit/5c880266f9968a2e9b102db7c0eea2c7b0f09a43)] - docs(plugin): use async (#1730) (TZ | 天猪 <>) +- [[`ebb8adf`](http://github.com/eggjs/egg/commit/ebb8adfadcf21ba29997c65d5adc5a92235ffa8d)] - some changes of docs(what is egg) (#1734) (恬竹 <<2632807692@qq.com>>) +- [[`2da00fc`](http://github.com/eggjs/egg/commit/2da00fca45d9bc161cae5ab9754a3fcc0321b9c7)] - docs(framework): use new way (#1728) (TZ | 天猪 <>) +- [[`47fbee5`](http://github.com/eggjs/egg/commit/47fbee574b94d9f6420d44e7a8f0ccec035d94f4)] - docs(cluster-client): use async (#1727) (TZ | 天猪 <>) +- [[`1420682`](http://github.com/eggjs/egg/commit/1420682dc5b6fb14342373d9b70614c3de0c015b)] - docs(ipc): use async (#1722) (TZ | 天猪 <>) +- [[`503b69b`](http://github.com/eggjs/egg/commit/503b69b2e5c3f59b9c3c307a50e711cd8eb8d967)] - feat: dump application router json (fengmk2 <>) +- [[`76ff783`](http://github.com/eggjs/egg/commit/76ff783b80a9d9ffc01db1b434c25fedd6e27ca7)] - fix: run dumpConfig at the last ready callback (fengmk2 <>) +- [[`50efe4c`](http://github.com/eggjs/egg/commit/50efe4ceb9a4c8ec902a503db7ad10ffe7819e1a)] - docs(httpclient): use async (#1724) (TZ | 天猪 <>) +- [[`d043148`](http://github.com/eggjs/egg/commit/d043148b8ee69614098b39604dd6b7d7e1a84810)] - docs: remove async-function (#1713) (TZ | 天猪 <>) +- [[`e3ef3ec`](http://github.com/eggjs/egg/commit/e3ef3ec65c5e2874c813f6cda18b61b630d137be)] - docs(restful): use async (#1709) (TZ | 天猪 <>) +- [[`b042937`](http://github.com/eggjs/egg/commit/b042937b1e77b8206206a248c9f3e3ab82b7d6d8)] - docs(error-handling): use async (#1721) (TZ | 天猪 <>) +- [[`80ab243`](http://github.com/eggjs/egg/commit/80ab2439d508e9e0574df31061b5bb14988c2e3e)] - docs(i18n): use async (#1720) (TZ | 天猪 <>) +- [[`6741999`](http://github.com/eggjs/egg/commit/67419996a3abd403ab8d67755ecb98c3a9b97338)] - docs(logger): use async (#1719) (TZ | 天猪 <>) +- [[`f39c105`](http://github.com/eggjs/egg/commit/f39c105067e08fe416f86d0a415f5475ce66ba17)] - docs(view): use async (#1717) (TZ | 天猪 <>) +- [[`cf3de0f`](http://github.com/eggjs/egg/commit/cf3de0f248e3435a7d6ac41ece16dea55f5e86c9)] - docs(unittest): use async (#1716) (TZ | 天猪 <>) +- [[`cb9c9a4`](http://github.com/eggjs/egg/commit/cb9c9a43015a47347273bf8a09d971205b0d57ec)] - docs(mysql): use async (#1711) (TZ | 天猪 <>) ## 2017-11-20, Version 2.0.0, @dead-horse ### Notable changes -* **performance** - * By removing the wrapper code of `co` library, performance increase over 30% (which not include the performance boost coming with Node 8), see [#14](https://github.com/eggjs/benchmark/pull/14) and [benchmark](https://eggjs.github.io/benchmark/plot/) - -* **feature** - * [BREAKING CHANGE] drop node <8 support - * upgrade to egg-core@4(base on koa 2), but still supports all the usages in egg 1 - * upgrade built-in plugins to adapt egg@2 - * `runInBackground` use location as scope name when anonymous - -* **fix** - * dump async function as AsyncFunction - -* **document** - * migrate some documents to async function - * split plugin and plugin development - * refactor the description about cluster client @vincenthou - * add document for how to customize error handler - * translate cookie and session @zhang-z - * translate basics/schedule.md, thanks @Azard - -### Commits - - * [[`8197826`](http://github.com/eggjs/egg/commit/8197826a8dca062c91ba45c235cec66a93f335a4)] - docs: refine egg-and-koa with egg 2 (#1686) (Yiyu He <>) - * [[`757f275`](http://github.com/eggjs/egg/commit/757f275a16741c670f210876408aaeefe5797a23)] - fix: dump async function as AsyncFunction (#1687) (Yiyu He <>) - * [[`12edd64`](http://github.com/eggjs/egg/commit/12edd64915164df6b2d5fed9e179e90954f25687)] - test: use async function instead of generator function (#1684) (Yiyu He <>) - * [[`5513456`](http://github.com/eggjs/egg/commit/5513456e2c702fdc1b7a500f8d8d58048d1041fa)] - feat: runInBackground use location as scope name when anonymous (#1683) (Yiyu He <>) - * [[`212b077`](http://github.com/eggjs/egg/commit/212b077993cff01c08c55fa4545c324adb96322c)] - doc: Add th.yml (#1682) (NatPi <<31546528+NatJNP@users.noreply.github.com>>) - * [[`3ddd67f`](http://github.com/eggjs/egg/commit/3ddd67fbbb83a783541118a05d7e0febb2fde7f3)] - docs(advanced/cluster-client): refactor the description about cluster client (#1417) (vincent.hou <>) - * [[`3d948e4`](http://github.com/eggjs/egg/commit/3d948e44e55fbb88c318a8f14fa7a0b0a8b71b4e)] - docs(plugin): split plugin and plugin development (#1663) (TZ | 天猪 <>) - * [[`b1343ad`](http://github.com/eggjs/egg/commit/b1343ad55f08b15f8084104c54db0b5975716323)] - docs(core/unittest): translate unittest.md (#1660) (freebyron <>) - * [[`fb2d96a`](http://github.com/eggjs/egg/commit/fb2d96ae8e1759edc9126a2920f9028b6e4d15df)] - docs(app-start): generator -> async (#1662) (TZ | 天猪 <>) - * [[`12c0a8a`](http://github.com/eggjs/egg/commit/12c0a8afb8cd332037670f7db8e8662566c1407f)] - docs(quickstart): fix app.Service (#1661) (TZ | 天猪 <>) - * [[`49b0071`](http://github.com/eggjs/egg/commit/49b00712de6eed7c386b07c7c91082ef36cc667f)] - docs(core/cookie-and-session): translate section Cookie (#1562) (Zhongyuan <>) - * [[`ac55d5e`](http://github.com/eggjs/egg/commit/ac55d5eb0b90e2333e3d92523075615e80835647)] - docs: fix typo in async function (#1657) (BccSafe <>) - * [[`9f362d8`](http://github.com/eggjs/egg/commit/9f362d878b61e1144ceab851215dbafb974fb85f)] - docs(basics/schedule.md): translate (#1648) (Weilun Xiong <>) - * [[`448d094`](http://github.com/eggjs/egg/commit/448d0945c0030d2f2bdf8e0f85ccfcbde4ba2b25)] - deps: upgrade all plugins to adapt egg@2 (#1653) (Yiyu He <>) - * [[`4993ee8`](http://github.com/eggjs/egg/commit/4993ee8fae81bf14f92c86ac1d4d952d62e1d165)] - docs(quickstart): generator -> async (#1650) (TZ | 天猪 <>) - * [[`8c6f16d`](http://github.com/eggjs/egg/commit/8c6f16d64834d46b0689ce079cc5d71155848ac8)] - docs: how to customize error handler (#1651) (Yiyu He <>) - * [[`8e8869a`](http://github.com/eggjs/egg/commit/8e8869a4d73908503cf1f60de3be49461639ca08)] - refactor: upgrade egg-core@4 (#1631) (Yiyu He <>) +- **performance** + - By removing the wrapper code of `co` library, performance increase over 30% (which not include the performance boost coming with Node 8), see [#14](https://github.com/eggjs/benchmark/pull/14) and [benchmark](https://eggjs.github.io/benchmark/plot/) + +- **feature** + - [BREAKING CHANGE] drop node <8 support + - upgrade to egg-core@4(base on koa 2), but still supports all the usages in egg 1 + - upgrade built-in plugins to adapt egg@2 + - `runInBackground` use location as scope name when anonymous + +- **fix** + - dump async function as AsyncFunction + +- **document** + - migrate some documents to async function + - split plugin and plugin development + - refactor the description about cluster client @vincenthou + - add document for how to customize error handler + - translate cookie and session @zhang-z + - translate basics/schedule.md, thanks @Azard + +### Commits + +- [[`8197826`](http://github.com/eggjs/egg/commit/8197826a8dca062c91ba45c235cec66a93f335a4)] - docs: refine egg-and-koa with egg 2 (#1686) (Yiyu He <>) +- [[`757f275`](http://github.com/eggjs/egg/commit/757f275a16741c670f210876408aaeefe5797a23)] - fix: dump async function as AsyncFunction (#1687) (Yiyu He <>) +- [[`12edd64`](http://github.com/eggjs/egg/commit/12edd64915164df6b2d5fed9e179e90954f25687)] - test: use async function instead of generator function (#1684) (Yiyu He <>) +- [[`5513456`](http://github.com/eggjs/egg/commit/5513456e2c702fdc1b7a500f8d8d58048d1041fa)] - feat: runInBackground use location as scope name when anonymous (#1683) (Yiyu He <>) +- [[`212b077`](http://github.com/eggjs/egg/commit/212b077993cff01c08c55fa4545c324adb96322c)] - doc: Add th.yml (#1682) (NatPi <<31546528+NatJNP@users.noreply.github.com>>) +- [[`3ddd67f`](http://github.com/eggjs/egg/commit/3ddd67fbbb83a783541118a05d7e0febb2fde7f3)] - docs(advanced/cluster-client): refactor the description about cluster client (#1417) (vincent.hou <>) +- [[`3d948e4`](http://github.com/eggjs/egg/commit/3d948e44e55fbb88c318a8f14fa7a0b0a8b71b4e)] - docs(plugin): split plugin and plugin development (#1663) (TZ | 天猪 <>) +- [[`b1343ad`](http://github.com/eggjs/egg/commit/b1343ad55f08b15f8084104c54db0b5975716323)] - docs(core/unittest): translate unittest.md (#1660) (freebyron <>) +- [[`fb2d96a`](http://github.com/eggjs/egg/commit/fb2d96ae8e1759edc9126a2920f9028b6e4d15df)] - docs(app-start): generator -> async (#1662) (TZ | 天猪 <>) +- [[`12c0a8a`](http://github.com/eggjs/egg/commit/12c0a8afb8cd332037670f7db8e8662566c1407f)] - docs(quickstart): fix app.Service (#1661) (TZ | 天猪 <>) +- [[`49b0071`](http://github.com/eggjs/egg/commit/49b00712de6eed7c386b07c7c91082ef36cc667f)] - docs(core/cookie-and-session): translate section Cookie (#1562) (Zhongyuan <>) +- [[`ac55d5e`](http://github.com/eggjs/egg/commit/ac55d5eb0b90e2333e3d92523075615e80835647)] - docs: fix typo in async function (#1657) (BccSafe <>) +- [[`9f362d8`](http://github.com/eggjs/egg/commit/9f362d878b61e1144ceab851215dbafb974fb85f)] - docs(basics/schedule.md): translate (#1648) (Weilun Xiong <>) +- [[`448d094`](http://github.com/eggjs/egg/commit/448d0945c0030d2f2bdf8e0f85ccfcbde4ba2b25)] - deps: upgrade all plugins to adapt egg@2 (#1653) (Yiyu He <>) +- [[`4993ee8`](http://github.com/eggjs/egg/commit/4993ee8fae81bf14f92c86ac1d4d952d62e1d165)] - docs(quickstart): generator -> async (#1650) (TZ | 天猪 <>) +- [[`8c6f16d`](http://github.com/eggjs/egg/commit/8c6f16d64834d46b0689ce079cc5d71155848ac8)] - docs: how to customize error handler (#1651) (Yiyu He <>) +- [[`8e8869a`](http://github.com/eggjs/egg/commit/8e8869a4d73908503cf1f60de3be49461639ca08)] - refactor: upgrade egg-core@4 (#1631) (Yiyu He <>) ## 2017-11-08, Version 1.11.0, @dead-horse ### Notable changes -* **feature** - * export global namespace at d.ts @atian25 +- **feature** + - export global namespace at d.ts @atian25 ### Commits - * [[`b131a4c`](http://github.com/eggjs/egg/commit/b131a4cec51cc783dcd4ccb8756439063c5b875c)] - feat: export global namespace at d.ts (#1633) (TZ | 天猪 <>) +- [[`b131a4c`](http://github.com/eggjs/egg/commit/b131a4cec51cc783dcd4ccb8756439063c5b875c)] - feat: export global namespace at d.ts (#1633) (TZ | 天猪 <>) ## 2017-11-08, Version 1.10.1, @dead-horse ### Notable changes -* **fix** - * use `app.options` instead of deprecated `app._options` -* **document** - * translate core/cluster-and-ipc.md, thanks @lslxdx +- **fix** + - use `app.options` instead of deprecated `app._options` +- **document** + - translate core/cluster-and-ipc.md, thanks @lslxdx ### Commits - * [[`9eec677`](http://github.com/eggjs/egg/commit/9eec677757ddbde6f7ddcff2c6a698087e07b70e)] - fix: use `app.options` instead of `app._options` (#1625) (Yiyu He <>) - * [[`fd1ff63`](http://github.com/eggjs/egg/commit/fd1ff638920fef4a3258767df982b87e70614215)] - test: fix tsc test case (#1620) (Yiyu He <>) - * [[`6804bd3`](http://github.com/eggjs/egg/commit/6804bd36cfc7a9bd54b3be2d9ce828d4e951f8b8)] - test: add node 9 and drop node 7 (#1602) (fengmk2 <>) - * [[`3878862`](http://github.com/eggjs/egg/commit/38788621ccf06fd6ac8f4068de3e49c5668e1915)] - docs: translate core/cluster-and-ipc.md (#1594) (lslxdx <>) +- [[`9eec677`](http://github.com/eggjs/egg/commit/9eec677757ddbde6f7ddcff2c6a698087e07b70e)] - fix: use `app.options` instead of `app._options` (#1625) (Yiyu He <>) +- [[`fd1ff63`](http://github.com/eggjs/egg/commit/fd1ff638920fef4a3258767df982b87e70614215)] - test: fix tsc test case (#1620) (Yiyu He <>) +- [[`6804bd3`](http://github.com/eggjs/egg/commit/6804bd36cfc7a9bd54b3be2d9ce828d4e951f8b8)] - test: add node 9 and drop node 7 (#1602) (fengmk2 <>) +- [[`3878862`](http://github.com/eggjs/egg/commit/38788621ccf06fd6ac8f4068de3e49c5668e1915)] - docs: translate core/cluster-and-ipc.md (#1594) (lslxdx <>) ## 2017-10-24, Version 1.10.0, @popomore ### Notable changes -* **feature** - * add Subscription @popomore -* **document** - * multipart example @dead_horse - * fix document @atian25 @beilunyang - * improve schedule document @atian25 +- **feature** + - add Subscription @popomore +- **document** + - multipart example @dead_horse + - fix document @atian25 @beilunyang + - improve schedule document @atian25 ### Commits - * [[`6dd1594a5`](http://github.com/eggjs/egg/commit/6dd1594a5c300f24e668b3679c7ae8df733b6a39)] - docs: fix egg-scripts (#1552) (TZ | 天猪 <>) - * [[`46ed6fac9`](http://github.com/eggjs/egg/commit/46ed6fac9f94d300a23903a71cfafdb5c8b1ba91)] - feat: add Subscription (#1469) (Haoliang Gao <>) - * [[`c508f9fa7`](http://github.com/eggjs/egg/commit/c508f9fa7dedbc8c3c4f6319b7233a034db463b4)] - docs: fix csrf (#1551) (TZ | 天猪 <>) - * [[`7fb9bbf71`](http://github.com/eggjs/egg/commit/7fb9bbf71219debf35b4e864a65be22e24a0480a)] - docs: fix typo (#1537) (悖论 <<786220806@qq.com>>) - * [[`68c0e1a9c`](http://github.com/eggjs/egg/commit/68c0e1a9c053618133d3484043abfb77e3372a22)] - docs: adjust new schedule (#1477) (TZ | 天猪 <>) - * [[`aeae948ec`](http://github.com/eggjs/egg/commit/aeae948ec986f5f7204ad6a0f748403b8e6e6fe1)] - docs: adjust middleware config at framework (#1523) (TZ | 天猪 <>) - * [[`7b37d2393`](http://github.com/eggjs/egg/commit/7b37d2393f59f3c5efbc84cf1d5f51e9332b0cd8)] - docs: multipart example use yield parts() (#1518) (Yiyu He <>) - * [[`6846badc8`](http://github.com/eggjs/egg/commit/6846badc8da89b00483aa7be5c69b1cd2f06d797)] - docs: add plugin.js description (#1499) (TZ | 天猪 <>) +- [[`6dd1594a5`](http://github.com/eggjs/egg/commit/6dd1594a5c300f24e668b3679c7ae8df733b6a39)] - docs: fix egg-scripts (#1552) (TZ | 天猪 <>) +- [[`46ed6fac9`](http://github.com/eggjs/egg/commit/46ed6fac9f94d300a23903a71cfafdb5c8b1ba91)] - feat: add Subscription (#1469) (Haoliang Gao <>) +- [[`c508f9fa7`](http://github.com/eggjs/egg/commit/c508f9fa7dedbc8c3c4f6319b7233a034db463b4)] - docs: fix csrf (#1551) (TZ | 天猪 <>) +- [[`7fb9bbf71`](http://github.com/eggjs/egg/commit/7fb9bbf71219debf35b4e864a65be22e24a0480a)] - docs: fix typo (#1537) (悖论 <<786220806@qq.com>>) +- [[`68c0e1a9c`](http://github.com/eggjs/egg/commit/68c0e1a9c053618133d3484043abfb77e3372a22)] - docs: adjust new schedule (#1477) (TZ | 天猪 <>) +- [[`aeae948ec`](http://github.com/eggjs/egg/commit/aeae948ec986f5f7204ad6a0f748403b8e6e6fe1)] - docs: adjust middleware config at framework (#1523) (TZ | 天猪 <>) +- [[`7b37d2393`](http://github.com/eggjs/egg/commit/7b37d2393f59f3c5efbc84cf1d5f51e9332b0cd8)] - docs: multipart example use yield parts() (#1518) (Yiyu He <>) +- [[`6846badc8`](http://github.com/eggjs/egg/commit/6846badc8da89b00483aa7be5c69b1cd2f06d797)] - docs: add plugin.js description (#1499) (TZ | 天猪 <>) ## 2017-09-25, Version 1.9.0, @gxcsoccer ### Notable changes -* **feature** - * make cluster client configurable in egg - * don’t force logger to use INFO level in prod -* **document** - * correct sample codes, by @Jawnkuin - * fix devtools debug, by @atian25 - * adjust debug docs with new egg-bin debug, by @atian25 - * fix port should be number, @atian25 +- **feature** + - make cluster client configurable in egg + - don’t force logger to use INFO level in prod +- **document** + - correct sample codes, by @Jawnkuin + - fix devtools debug, by @atian25 + - adjust debug docs with new egg-bin debug, by @atian25 + - fix port should be number, @atian25 ### Commits - * [[`21425e7`](https://github.com/eggjs/egg/commit/21425e7a9c451cfa07f3cb580d0b770eb5b0c890)] - feat: make cluster client configurable in egg (#1459) (gxcsoccer <>) - * [[`d0797b1`](https://github.com/eggjs/egg/commit/d0797b1c2d078d1bea97c104471388bedc5e61c9)] - docs: correct sample codes (#1434) (Jawnkuin <>) - * [[`6eac07e`](https://github.com/eggjs/egg/commit/6eac07eb287ecf158b2c182a0e36a81fa14700ce)] - refactor: httpclient args tracer to be enforced (#1421) (hui <>) - * [[`c56274b`](https://github.com/eggjs/egg/commit/c56274bb818526370f857b926d178ff520b3bea8)] - docs(development): fix devtools debug (#1428) (TZ | 天猪 <>) - * [[`e3f29de`](https://github.com/eggjs/egg/commit/e3f29de9bbbfb67c641cf54272883759d7256d89)] - docs(development): adjust debug docs with new egg-bin debug (#1427) (AnzerWall <>) - * [[`5a9531a`](https://github.com/eggjs/egg/commit/5a9531abbec83fbff08ddb6feb475f87498d2a3d)] - feat: don’t force logger to use INFO level in prod (#1218) (TZ | 天猪 <>) - * [[`95fbd47`](https://github.com/eggjs/egg/commit/95fbd47f4c20797df17dd210f30a40f43d1d8900)] - docs(deployment): port should be number (#1424) (TZ | 天猪 <>) +- [[`21425e7`](https://github.com/eggjs/egg/commit/21425e7a9c451cfa07f3cb580d0b770eb5b0c890)] - feat: make cluster client configurable in egg (#1459) (gxcsoccer <>) +- [[`d0797b1`](https://github.com/eggjs/egg/commit/d0797b1c2d078d1bea97c104471388bedc5e61c9)] - docs: correct sample codes (#1434) (Jawnkuin <>) +- [[`6eac07e`](https://github.com/eggjs/egg/commit/6eac07eb287ecf158b2c182a0e36a81fa14700ce)] - refactor: httpclient args tracer to be enforced (#1421) (hui <>) +- [[`c56274b`](https://github.com/eggjs/egg/commit/c56274bb818526370f857b926d178ff520b3bea8)] - docs(development): fix devtools debug (#1428) (TZ | 天猪 <>) +- [[`e3f29de`](https://github.com/eggjs/egg/commit/e3f29de9bbbfb67c641cf54272883759d7256d89)] - docs(development): adjust debug docs with new egg-bin debug (#1427) (AnzerWall <>) +- [[`5a9531a`](https://github.com/eggjs/egg/commit/5a9531abbec83fbff08ddb6feb475f87498d2a3d)] - feat: don’t force logger to use INFO level in prod (#1218) (TZ | 天猪 <>) +- [[`95fbd47`](https://github.com/eggjs/egg/commit/95fbd47f4c20797df17dd210f30a40f43d1d8900)] - docs(deployment): port should be number (#1424) (TZ | 天猪 <>) ## 2017-09-11, Version 1.8.0, @leoner ### Notable changes -* **feature** - * support app.httpclient and agent.httpclient auto set tracer -* **fix** - * should extends from egg-core BaseContextClass -* **document** - * English documents `basics/objects`,`core/docs-logger` and `core/httpclient` +- **feature** + - support app.httpclient and agent.httpclient auto set tracer +- **fix** + - should extends from egg-core BaseContextClass +- **document** + - English documents `basics/objects`,`core/docs-logger` and `core/httpclient` have been translated by @DarrenWong, @Azard and @gztchan - * documents typo fixed and improved by @vincenthou, @waitingsong and @hyj1991 + - documents typo fixed and improved by @vincenthou, @waitingsong and @hyj1991 ### Commits - * [[`54be7dc09`](http://github.com/eggjs/egg/commit/54be7dc099f47fb65b9bc3d9bb29de4d70ac25cd)] - docs(core/cluster-and-ipc): fix some typo (#1415) (vincent.hou <>) - * [[`6cf17c11a`](http://github.com/eggjs/egg/commit/6cf17c11af51220904881ed99aa65cac0f212c2b)] - docs: (core/httpclient): [translate] Done (#1409) (Darren Wong <>) - * [[`105e1947e`](http://github.com/eggjs/egg/commit/105e1947ee0863ebd6c0a1111f218b025e0e9989)] - docs: translate basics/objects (#1238) (Weilun Xiong <>) - * [[`f7c0d8520`](http://github.com/eggjs/egg/commit/f7c0d85209c9e96f7812c4a2996f000a2667770d)] - feat: support app.httpclient and agent.httpclient auto set tracer (#1393) (hui <>) - * [[`3aaee8fbe`](http://github.com/eggjs/egg/commit/3aaee8fbea4aee8b5c40921670642772835bf40d)] - fix: should extends from egg-core BaseContextClass (#1392) (fengmk2 <>) - * [[`a9936a383`](http://github.com/eggjs/egg/commit/a9936a383174fd0b2c201ee759bc5174486970a1)] - fix: typo (#1388) (waiting <>) - * [[`eef30faf6`](http://github.com/eggjs/egg/commit/eef30faf69b41f4a352a592ad65d097698d27303)] - docs: adjust webstorm debug config (#1367) (TZ | 天猪 <>) - * [[`499454379`](http://github.com/eggjs/egg/commit/499454379b2234a80d3946933f7511ac83c292d6)] - docs: curl(url, opts) add parameter introduction (#1351) (#1352) (hyj1991 <<66cfat66@gmail.com>>) - * [[`4daf497eb`](http://github.com/eggjs/egg/commit/4daf497eb32c05c73911a01e861b9cf761ede451)] - docs(en/core/docs-logger): finish logger.md translation in English (#1254) (Tony Chan <>) - * [[`aaacd56c9`](http://github.com/eggjs/egg/commit/aaacd56c9c60dbf0cbfd0d1fcc77366a3e3993fe)] - docs: remove egg-scripts env default description (#1318) (TZ | 天猪 <>) - * [[`4feae70b8`](http://github.com/eggjs/egg/commit/4feae70b8c8e69890053bff9f3df9cc7024d69cd)] - docs: add egg-scripts to deployment (#1279) (TZ | 天猪 <>) - * [[`08ed1b3c6`](http://github.com/eggjs/egg/commit/08ed1b3c68e242eba187640c9f6cf8a0acd7489f)] - docs(unittest): typo of egg-mock (#1284) (TZ | 天猪 <>) - * [[`734854c84`](http://github.com/eggjs/egg/commit/734854c84ef8b0107df3101b6aa212d96574b317)] - docs(unittest): add bootstrap usage (#1278) (Yiyu He <>) - * [[`ebbbcd574`](http://github.com/eggjs/egg/commit/ebbbcd574f5bbd4d91bec345e8b35f9adc48d6c0)] - chore: skip docs deploy at ci cron (#1268) (TZ | 天猪 <>) +- [[`54be7dc09`](http://github.com/eggjs/egg/commit/54be7dc099f47fb65b9bc3d9bb29de4d70ac25cd)] - docs(core/cluster-and-ipc): fix some typo (#1415) (vincent.hou <>) +- [[`6cf17c11a`](http://github.com/eggjs/egg/commit/6cf17c11af51220904881ed99aa65cac0f212c2b)] - docs: (core/httpclient): [translate] Done (#1409) (Darren Wong <>) +- [[`105e1947e`](http://github.com/eggjs/egg/commit/105e1947ee0863ebd6c0a1111f218b025e0e9989)] - docs: translate basics/objects (#1238) (Weilun Xiong <>) +- [[`f7c0d8520`](http://github.com/eggjs/egg/commit/f7c0d85209c9e96f7812c4a2996f000a2667770d)] - feat: support app.httpclient and agent.httpclient auto set tracer (#1393) (hui <>) +- [[`3aaee8fbe`](http://github.com/eggjs/egg/commit/3aaee8fbea4aee8b5c40921670642772835bf40d)] - fix: should extends from egg-core BaseContextClass (#1392) (fengmk2 <>) +- [[`a9936a383`](http://github.com/eggjs/egg/commit/a9936a383174fd0b2c201ee759bc5174486970a1)] - fix: typo (#1388) (waiting <>) +- [[`eef30faf6`](http://github.com/eggjs/egg/commit/eef30faf69b41f4a352a592ad65d097698d27303)] - docs: adjust webstorm debug config (#1367) (TZ | 天猪 <>) +- [[`499454379`](http://github.com/eggjs/egg/commit/499454379b2234a80d3946933f7511ac83c292d6)] - docs: curl(url, opts) add parameter introduction (#1351) (#1352) (hyj1991 <<66cfat66@gmail.com>>) +- [[`4daf497eb`](http://github.com/eggjs/egg/commit/4daf497eb32c05c73911a01e861b9cf761ede451)] - docs(en/core/docs-logger): finish logger.md translation in English (#1254) (Tony Chan <>) +- [[`aaacd56c9`](http://github.com/eggjs/egg/commit/aaacd56c9c60dbf0cbfd0d1fcc77366a3e3993fe)] - docs: remove egg-scripts env default description (#1318) (TZ | 天猪 <>) +- [[`4feae70b8`](http://github.com/eggjs/egg/commit/4feae70b8c8e69890053bff9f3df9cc7024d69cd)] - docs: add egg-scripts to deployment (#1279) (TZ | 天猪 <>) +- [[`08ed1b3c6`](http://github.com/eggjs/egg/commit/08ed1b3c68e242eba187640c9f6cf8a0acd7489f)] - docs(unittest): typo of egg-mock (#1284) (TZ | 天猪 <>) +- [[`734854c84`](http://github.com/eggjs/egg/commit/734854c84ef8b0107df3101b6aa212d96574b317)] - docs(unittest): add bootstrap usage (#1278) (Yiyu He <>) +- [[`ebbbcd574`](http://github.com/eggjs/egg/commit/ebbbcd574f5bbd4d91bec345e8b35f9adc48d6c0)] - chore: skip docs deploy at ci cron (#1268) (TZ | 天猪 <>) ## 2017-07-27, Version 1.7.0, @popomore ### Notable changes -* **feature** - * Support listen options in config.js -* **improve** - * `app.HttpClient` can be overwritten -* **document** - * Document improvement - * English documents have been translated by @gztchan +- **feature** + - Support listen options in config.js +- **improve** + - `app.HttpClient` can be overwritten +- **document** + - Document improvement + - English documents have been translated by @gztchan ### Commits - * [[`dd07cacb2`](http://github.com/eggjs/egg/commit/dd07cacb209565cc8bdc240b2a3bd7f624a3e56c)] - docs: fix typo on CONTRIBUTING.zh-CN.md (#1266) (SuperEwe <>) - * [[`773343061`](http://github.com/eggjs/egg/commit/7733430614d62392fa1b06568e223ce2ae5b3709)] - docs: only deploy docs at 8 (#1252) (TZ | 天猪 <>) - * [[`4f2ebfda8`](http://github.com/eggjs/egg/commit/4f2ebfda81c067ba500ee22ac30c8b201f746cac)] - docs: fix const define (#1249) (TZ | 天猪 <>) - * [[`45bea3cb5`](http://github.com/eggjs/egg/commit/45bea3cb55636a09160bfc66befca476994dacc8)] - docs(core-deployment): translate deployment.md in English (#1235) (Tony Chan <>) - * [[`dda386e42`](http://github.com/eggjs/egg/commit/dda386e425ce96019f3d068e66603f80af966571)] - test: add test and doc for listen options (#1246) (Haoliang Gao <>) - * [[`3ef1de952`](http://github.com/eggjs/egg/commit/3ef1de95247aa3e3fdcbda71fe83e58a892a13d6)] - feat: set cluster options, include path, port, hostname (#1231) (Haoliang Gao <>) - * [[`e9f93cf83`](http://github.com/eggjs/egg/commit/e9f93cf83d46fd84c8c6b10ec2e7e3eb2bf24f9d)] - refactor: export app.HttpClient that can be overwritten (#1234) (Haoliang Gao <>) - * [[`96b3786eb`](http://github.com/eggjs/egg/commit/96b3786eb9640c9ec2d71a5a0a0b18ee32e9e3ad)] - docs(core/error-handling): translate error-handling.md in English (#1228) (Tony Chan <>) - * [[`c3c9fce55`](http://github.com/eggjs/egg/commit/c3c9fce557a8d8c57b2a5e5391d1c11a81ceeaa7)] - docs(controller): examples use controller class (#1221) (Yiyu He <>) - * [[`24f279005`](http://github.com/eggjs/egg/commit/24f2790051c0d248f6df9850ffe8513dc11e5780)] - docs: new VScode 1.14 default protocol changed. (#1212) (Anto <>) - * [[`2b78b4cf8`](http://github.com/eggjs/egg/commit/2b78b4cf8275171ddf788550745edc3aef948ca7)] - docs: Fix config name from egg-Plugin to eggPlugin in plugin's doc (#1215) (hansen <>) +- [[`dd07cacb2`](http://github.com/eggjs/egg/commit/dd07cacb209565cc8bdc240b2a3bd7f624a3e56c)] - docs: fix typo on CONTRIBUTING.zh-CN.md (#1266) (SuperEwe <>) +- [[`773343061`](http://github.com/eggjs/egg/commit/7733430614d62392fa1b06568e223ce2ae5b3709)] - docs: only deploy docs at 8 (#1252) (TZ | 天猪 <>) +- [[`4f2ebfda8`](http://github.com/eggjs/egg/commit/4f2ebfda81c067ba500ee22ac30c8b201f746cac)] - docs: fix const define (#1249) (TZ | 天猪 <>) +- [[`45bea3cb5`](http://github.com/eggjs/egg/commit/45bea3cb55636a09160bfc66befca476994dacc8)] - docs(core-deployment): translate deployment.md in English (#1235) (Tony Chan <>) +- [[`dda386e42`](http://github.com/eggjs/egg/commit/dda386e425ce96019f3d068e66603f80af966571)] - test: add test and doc for listen options (#1246) (Haoliang Gao <>) +- [[`3ef1de952`](http://github.com/eggjs/egg/commit/3ef1de95247aa3e3fdcbda71fe83e58a892a13d6)] - feat: set cluster options, include path, port, hostname (#1231) (Haoliang Gao <>) +- [[`e9f93cf83`](http://github.com/eggjs/egg/commit/e9f93cf83d46fd84c8c6b10ec2e7e3eb2bf24f9d)] - refactor: export app.HttpClient that can be overwritten (#1234) (Haoliang Gao <>) +- [[`96b3786eb`](http://github.com/eggjs/egg/commit/96b3786eb9640c9ec2d71a5a0a0b18ee32e9e3ad)] - docs(core/error-handling): translate error-handling.md in English (#1228) (Tony Chan <>) +- [[`c3c9fce55`](http://github.com/eggjs/egg/commit/c3c9fce557a8d8c57b2a5e5391d1c11a81ceeaa7)] - docs(controller): examples use controller class (#1221) (Yiyu He <>) +- [[`24f279005`](http://github.com/eggjs/egg/commit/24f2790051c0d248f6df9850ffe8513dc11e5780)] - docs: new VScode 1.14 default protocol changed. (#1212) (Anto <>) +- [[`2b78b4cf8`](http://github.com/eggjs/egg/commit/2b78b4cf8275171ddf788550745edc3aef948ca7)] - docs: Fix config name from egg-Plugin to eggPlugin in plugin's doc (#1215) (hansen <>) ## 2017-07-19, Version 1.6.1, @fengmk2 ### Notable changes -* **fix** - * make sure config.httpclient.httpAgent.timeout >= 30000, and distinguish +- **fix** + - make sure config.httpclient.httpAgent.timeout >= 30000, and distinguish options: request, httpAgent and httpsAgent on `config.httpclient`. ### Commits - * [[`988b8c8`](http://github.com/eggjs/egg/commit/988b8c84d0f63ce0e83e00bd12cff65ebf4f2ff5)] - fix: make sure config.httpclient.httpAgent.timeout >= 30000 (#1165) (fengmk2 <>) - * [[`894005c`](http://github.com/eggjs/egg/commit/894005c8e683e764ec234c915afce89b57343f98)] - docs: (core/i18n): [translate] Done (#1194) (Darren Wong <>) - * [[`410633b`](http://github.com/eggjs/egg/commit/410633b3e47098abc30d83429895b543431929ec)] - chore: kill ssh-agent after deploy (#1204) (Haoliang Gao <>) - * [[`05f4785`](http://github.com/eggjs/egg/commit/05f47858a6d74041a10539443a9ea2e195826bc4)] - chore: add travis_wait to avoid deploying document timeout (#1201) (Haoliang Gao <>) - * [[`367e1d6`](http://github.com/eggjs/egg/commit/367e1d66ef3bdb49ee41758246cdaf49e04ea140)] - docs: fix typo (#1191) (BingqiChan <>) +- [[`988b8c8`](http://github.com/eggjs/egg/commit/988b8c84d0f63ce0e83e00bd12cff65ebf4f2ff5)] - fix: make sure config.httpclient.httpAgent.timeout >= 30000 (#1165) (fengmk2 <>) +- [[`894005c`](http://github.com/eggjs/egg/commit/894005c8e683e764ec234c915afce89b57343f98)] - docs: (core/i18n): [translate] Done (#1194) (Darren Wong <>) +- [[`410633b`](http://github.com/eggjs/egg/commit/410633b3e47098abc30d83429895b543431929ec)] - chore: kill ssh-agent after deploy (#1204) (Haoliang Gao <>) +- [[`05f4785`](http://github.com/eggjs/egg/commit/05f47858a6d74041a10539443a9ea2e195826bc4)] - chore: add travis_wait to avoid deploying document timeout (#1201) (Haoliang Gao <>) +- [[`367e1d6`](http://github.com/eggjs/egg/commit/367e1d66ef3bdb49ee41758246cdaf49e04ea140)] - docs: fix typo (#1191) (BingqiChan <>) ## 2017-07-04, Version 1.6.0, @fengmk2 ### Notable changes -* **feature** - * tsd add ctx.logger and logger.error support Error object - * ignore any key contains "secret" on dump config files - * show who define the property of the config on `run/application_config_meta.json` -* **fix** - * don't cache the intermediate locals for application - -### Commits - - * [[`5dc56fa`](http://github.com/eggjs/egg/commit/5dc56fac043eab22187f9ae1dd7e73d2160fd7ae)] - feat: ignore any key contains "secret" (#1156) (fengmk2 <>) - * [[`74c8a54`](http://github.com/eggjs/egg/commit/74c8a547cc90939253946a145655996b59373457)] - feat: dump `run/${type}_config_meta.json` (#1155) (Haoliang Gao <>) - * [[`b80bb14`](http://github.com/eggjs/egg/commit/b80bb1405c1f47c5596ff4a2c9540af7447430ec)] - fix: don't cache the intermediate locals for application (#1146) (Jackson Tian <>) - * [[`7c70beb`](http://github.com/eggjs/egg/commit/7c70beb26ecf2176cda7547f3163fec11aff450f)] - docs: change istanbul to nyc (#1150) (TZ | 天猪 <>) - * [[`c7a87a8`](http://github.com/eggjs/egg/commit/c7a87a8abade84769b34a1ef0ba50a3cc12dec49)] - docs: adjust objects docs (#1140) (TZ | 天猪 <>) - * [[`0052351`](http://github.com/eggjs/egg/commit/005235162dce4b0e87768a201c9a68c4291592d4)] - docs: improve plugin dependencies (#1061) (luicfer <>) - * [[`4322212`](http://github.com/eggjs/egg/commit/43222127b922b486d8f523230fed82ba453ee8d8)] - docs: add missing class in objects.md (kaiye <>) - * [[`daa8227`](http://github.com/eggjs/egg/commit/daa82278332d7617d6ebb3d07e8cdfd1e95cf644)] - feat(tsd): add ctx.logger and logger.error support Error object (#1108) (Eward Song <>) - * [[`7c2e436`](http://github.com/eggjs/egg/commit/7c2e43626d93049b5f91f59773ef02c4b0f478b3)] - docs: improve feature describe (#1102) (Yiyu He <>) - * [[`5ae7814`](http://github.com/eggjs/egg/commit/5ae7814632b1f92d534a496fe4f51c6737447aba)] - chore: comments in english (#1101) (Yiyu He <>) - * [[`9099be9`](http://github.com/eggjs/egg/commit/9099be91afa806d0a8258441d11e1da2318777ef)] - docs: unify config in quickstart (#1094) (Yiyu He <>) - * [[`c31bc15`](http://github.com/eggjs/egg/commit/c31bc15097c692d08596a277c69fbd44f9d3e2bf)] - test: wait logger to flush (#1090) (Haoliang Gao <>) - * [[`82d2158`](http://github.com/eggjs/egg/commit/82d2158e4c399ead9567b67dc27d13d1ef2e104e)] - docs: add Enclose.IO to Links (#1089) (Minqi Pan <>) +- **feature** + - tsd add ctx.logger and logger.error support Error object + - ignore any key contains "secret" on dump config files + - show who define the property of the config on `run/application_config_meta.json` +- **fix** + - don't cache the intermediate locals for application + +### Commits + +- [[`5dc56fa`](http://github.com/eggjs/egg/commit/5dc56fac043eab22187f9ae1dd7e73d2160fd7ae)] - feat: ignore any key contains "secret" (#1156) (fengmk2 <>) +- [[`74c8a54`](http://github.com/eggjs/egg/commit/74c8a547cc90939253946a145655996b59373457)] - feat: dump `run/${type}_config_meta.json` (#1155) (Haoliang Gao <>) +- [[`b80bb14`](http://github.com/eggjs/egg/commit/b80bb1405c1f47c5596ff4a2c9540af7447430ec)] - fix: don't cache the intermediate locals for application (#1146) (Jackson Tian <>) +- [[`7c70beb`](http://github.com/eggjs/egg/commit/7c70beb26ecf2176cda7547f3163fec11aff450f)] - docs: change istanbul to nyc (#1150) (TZ | 天猪 <>) +- [[`c7a87a8`](http://github.com/eggjs/egg/commit/c7a87a8abade84769b34a1ef0ba50a3cc12dec49)] - docs: adjust objects docs (#1140) (TZ | 天猪 <>) +- [[`0052351`](http://github.com/eggjs/egg/commit/005235162dce4b0e87768a201c9a68c4291592d4)] - docs: improve plugin dependencies (#1061) (luicfer <>) +- [[`4322212`](http://github.com/eggjs/egg/commit/43222127b922b486d8f523230fed82ba453ee8d8)] - docs: add missing class in objects.md (kaiye <>) +- [[`daa8227`](http://github.com/eggjs/egg/commit/daa82278332d7617d6ebb3d07e8cdfd1e95cf644)] - feat(tsd): add ctx.logger and logger.error support Error object (#1108) (Eward Song <>) +- [[`7c2e436`](http://github.com/eggjs/egg/commit/7c2e43626d93049b5f91f59773ef02c4b0f478b3)] - docs: improve feature describe (#1102) (Yiyu He <>) +- [[`5ae7814`](http://github.com/eggjs/egg/commit/5ae7814632b1f92d534a496fe4f51c6737447aba)] - chore: comments in english (#1101) (Yiyu He <>) +- [[`9099be9`](http://github.com/eggjs/egg/commit/9099be91afa806d0a8258441d11e1da2318777ef)] - docs: unify config in quickstart (#1094) (Yiyu He <>) +- [[`c31bc15`](http://github.com/eggjs/egg/commit/c31bc15097c692d08596a277c69fbd44f9d3e2bf)] - test: wait logger to flush (#1090) (Haoliang Gao <>) +- [[`82d2158`](http://github.com/eggjs/egg/commit/82d2158e4c399ead9567b67dc27d13d1ef2e104e)] - docs: add Enclose.IO to Links (#1089) (Minqi Pan <>) ## 2017-06-21, Version 1.5.0, @fengmk2 ### Notable changes -* **feature** - * better TypeScript support, add `index.d.ts` file. - * enable overrideMethod middleware by default. -* **document** - * Documents improved. - -### Commits - - * [[`1d02601`](http://github.com/eggjs/egg/commit/1d026019df76525d2d9117c260eb5d892388121c)] - tsd: add another properties of FileStream (#1080) (Rwing <>) - * [[`2b1644e`](http://github.com/eggjs/egg/commit/2b1644e6d56e6481ee97bce009c5f53b4dd18441)] - feat: add tsd (#1027) (Eward Song <>) - * [[`a4ba2a2`](http://github.com/eggjs/egg/commit/a4ba2a2a1ef7de49e196c01447fd73ab22ed6d34)] - feat: enable overrideMethod middleware by default (#1069) (fengmk2 <>) - * [[`bfb8df5`](http://github.com/eggjs/egg/commit/bfb8df58bcc7d7fe0fd6ff3453efcb54b715b4a0)] - docs: typo (#1060) (chenbin92 <>) - * [[`64d1b00`](http://github.com/eggjs/egg/commit/64d1b0026648e1128f09efb6e6c2cc7f632bf608)] - docs: add chrome devtools debug information (#1050) (仙森 <>) - * [[`4e510b2`](http://github.com/eggjs/egg/commit/4e510b22836096a47d562dbd5ca8affd28f94f9e)] - chore: use app.httpRequest() instead of supertest (#1041) (fengmk2 <>) - * [[`78a13d5`](http://github.com/eggjs/egg/commit/78a13d52c3b6e8b40a0015b285cda33a059c0ee4)] - docs: add more description at quickstart (#1042) (TZ | 天猪 <>) - * [[`ef7c864`](http://github.com/eggjs/egg/commit/ef7c864fbddf7e70afbd93a16d5176787328400d)] - docs: add ant.design link (#1037) (Haoliang Gao <>) - * [[`f1b510c`](http://github.com/eggjs/egg/commit/f1b510c34039259c5772021432ab71a7a62b89e8)] - feat: add config.logger.disableConsoleAfterReady (#1001) (fengmk2 <>) - * [[`4890eda`](http://github.com/eggjs/egg/commit/4890eda31b9bc60ea4a1a7f36460ec1bf86dc134)] - docs: Uniform the standards that we should acquire this parsed parame… (#1038) (Ruanyq <>) - * [[`9d705e4`](http://github.com/eggjs/egg/commit/9d705e4687cdb98d327fbd9a1061604828218dfc)] - test: make sure app close (#1030) (fengmk2 <>) - * [[`1d72e37`](http://github.com/eggjs/egg/commit/1d72e3799822e252934d6218a978c2bd21f378d3)] - docs: fix caseStyle link (#1033) (Desen Meng <>) - * [[`9b50725`](http://github.com/eggjs/egg/commit/9b507250725ef3beda0ee51ac0c2bc2b007b2ecb)] - docs: (tutorials/index.md & async-function.md ): [translate] Done (#1028) (Darren Wong <>) - * [[`3d04199`](http://github.com/eggjs/egg/commit/3d041992912d9aca1eb0edc6b226474022e08236)] - docs: typo (#1029) (Jerry Wu <>) - * [[`13b7c19`](http://github.com/eggjs/egg/commit/13b7c19531d772a2b932ada28e186a0dbd0cf5f5)] - test: node 8 (#976) (fengmk2 <>) - * [[`1b108a7`](http://github.com/eggjs/egg/commit/1b108a72a96d3d8241b332b8e728a9ec409efbb1)] - docs: remove api that is from egg-rest (#1022) (Haoliang Gao <>) - * [[`057bc47`](http://github.com/eggjs/egg/commit/057bc47e4c5e3ec8faae0de3807f656fa4ef41d4)] - test: add doc test (#989) (Haoliang Gao <>) - * [[`c6eb7b2`](http://github.com/eggjs/egg/commit/c6eb7b2f59f24fe0c6a787829d33cdf0cd4a2e77)] - doc: fix view config doc (#991) (当轩 <>) - * [[`52865b4`](http://github.com/eggjs/egg/commit/52865b47c4d336833ef1151bae9f30867359ceb6)] - docs: devtool inspect at 8.x (#1018) (TZ | 天猪 <>) - * [[`8a120fd`](http://github.com/eggjs/egg/commit/8a120fde73df60e23f8c5559a3281acaf0a393e0)] - docs: remove max time limit at schdule (#995) (TZ | 天猪 <>) - * [[`9084c24`](http://github.com/eggjs/egg/commit/9084c24dd10fcbcd0d436ada9639b59f36dd2edf)] - docs: add plugin list (#988) (Haoliang Gao <>) - * [[`20a5d91`](http://github.com/eggjs/egg/commit/20a5d9127f7454c899f7701f02b04eefa7c61fce)] - test: disable coverage for schedule (#987) (Haoliang Gao <>) - * [[`3de963f`](http://github.com/eggjs/egg/commit/3de963f3881ef6fb9c5b6fa207730c6695853239)] - docs(basics/structure.md): [translate] (#970) (Weilun Xiong <<330815461@qq.com>>) - * [[`2f232f3`](http://github.com/eggjs/egg/commit/2f232f30b0ba7e14ab07c43e34d363bac3906a43)] - docs: file must appear after other fiels when using getFileStream (#982) (Yiyu He <>) +- **feature** + - better TypeScript support, add `index.d.ts` file. + - enable overrideMethod middleware by default. +- **document** + - Documents improved. + +### Commits + +- [[`1d02601`](http://github.com/eggjs/egg/commit/1d026019df76525d2d9117c260eb5d892388121c)] - tsd: add another properties of FileStream (#1080) (Rwing <>) +- [[`2b1644e`](http://github.com/eggjs/egg/commit/2b1644e6d56e6481ee97bce009c5f53b4dd18441)] - feat: add tsd (#1027) (Eward Song <>) +- [[`a4ba2a2`](http://github.com/eggjs/egg/commit/a4ba2a2a1ef7de49e196c01447fd73ab22ed6d34)] - feat: enable overrideMethod middleware by default (#1069) (fengmk2 <>) +- [[`bfb8df5`](http://github.com/eggjs/egg/commit/bfb8df58bcc7d7fe0fd6ff3453efcb54b715b4a0)] - docs: typo (#1060) (chenbin92 <>) +- [[`64d1b00`](http://github.com/eggjs/egg/commit/64d1b0026648e1128f09efb6e6c2cc7f632bf608)] - docs: add chrome devtools debug information (#1050) (仙森 <>) +- [[`4e510b2`](http://github.com/eggjs/egg/commit/4e510b22836096a47d562dbd5ca8affd28f94f9e)] - chore: use app.httpRequest() instead of supertest (#1041) (fengmk2 <>) +- [[`78a13d5`](http://github.com/eggjs/egg/commit/78a13d52c3b6e8b40a0015b285cda33a059c0ee4)] - docs: add more description at quickstart (#1042) (TZ | 天猪 <>) +- [[`ef7c864`](http://github.com/eggjs/egg/commit/ef7c864fbddf7e70afbd93a16d5176787328400d)] - docs: add ant.design link (#1037) (Haoliang Gao <>) +- [[`f1b510c`](http://github.com/eggjs/egg/commit/f1b510c34039259c5772021432ab71a7a62b89e8)] - feat: add config.logger.disableConsoleAfterReady (#1001) (fengmk2 <>) +- [[`4890eda`](http://github.com/eggjs/egg/commit/4890eda31b9bc60ea4a1a7f36460ec1bf86dc134)] - docs: Uniform the standards that we should acquire this parsed parame… (#1038) (Ruanyq <>) +- [[`9d705e4`](http://github.com/eggjs/egg/commit/9d705e4687cdb98d327fbd9a1061604828218dfc)] - test: make sure app close (#1030) (fengmk2 <>) +- [[`1d72e37`](http://github.com/eggjs/egg/commit/1d72e3799822e252934d6218a978c2bd21f378d3)] - docs: fix caseStyle link (#1033) (Desen Meng <>) +- [[`9b50725`](http://github.com/eggjs/egg/commit/9b507250725ef3beda0ee51ac0c2bc2b007b2ecb)] - docs: (tutorials/index.md & async-function.md ): [translate] Done (#1028) (Darren Wong <>) +- [[`3d04199`](http://github.com/eggjs/egg/commit/3d041992912d9aca1eb0edc6b226474022e08236)] - docs: typo (#1029) (Jerry Wu <>) +- [[`13b7c19`](http://github.com/eggjs/egg/commit/13b7c19531d772a2b932ada28e186a0dbd0cf5f5)] - test: node 8 (#976) (fengmk2 <>) +- [[`1b108a7`](http://github.com/eggjs/egg/commit/1b108a72a96d3d8241b332b8e728a9ec409efbb1)] - docs: remove api that is from egg-rest (#1022) (Haoliang Gao <>) +- [[`057bc47`](http://github.com/eggjs/egg/commit/057bc47e4c5e3ec8faae0de3807f656fa4ef41d4)] - test: add doc test (#989) (Haoliang Gao <>) +- [[`c6eb7b2`](http://github.com/eggjs/egg/commit/c6eb7b2f59f24fe0c6a787829d33cdf0cd4a2e77)] - doc: fix view config doc (#991) (当轩 <>) +- [[`52865b4`](http://github.com/eggjs/egg/commit/52865b47c4d336833ef1151bae9f30867359ceb6)] - docs: devtool inspect at 8.x (#1018) (TZ | 天猪 <>) +- [[`8a120fd`](http://github.com/eggjs/egg/commit/8a120fde73df60e23f8c5559a3281acaf0a393e0)] - docs: remove max time limit at schdule (#995) (TZ | 天猪 <>) +- [[`9084c24`](http://github.com/eggjs/egg/commit/9084c24dd10fcbcd0d436ada9639b59f36dd2edf)] - docs: add plugin list (#988) (Haoliang Gao <>) +- [[`20a5d91`](http://github.com/eggjs/egg/commit/20a5d9127f7454c899f7701f02b04eefa7c61fce)] - test: disable coverage for schedule (#987) (Haoliang Gao <>) +- [[`3de963f`](http://github.com/eggjs/egg/commit/3de963f3881ef6fb9c5b6fa207730c6695853239)] - docs(basics/structure.md): [translate] (#970) (Weilun Xiong <<330815461@qq.com>>) +- [[`2f232f3`](http://github.com/eggjs/egg/commit/2f232f30b0ba7e14ab07c43e34d363bac3906a43)] - docs: file must appear after other fiels when using getFileStream (#982) (Yiyu He <>) ## 2017-05-28, Version 1.4.0, @dead-horse ### Notable changes -* **feature** - * use lru to aovid oom when httpclient dns cache enabled -* **fix** - * fix port is missed when httpclient dns cache enabled - * fix request url object will be changed when httpclient dns cache enabled - * set maxSockets defautl value to Number.MAX_SAFE_INTEGER -* **document** - * Documents improved. Thanks @DarrenWong, @zousandian, @lslxdx, @Azard, @johnnychen, @coogleyao, @DanielWLam, @m31271n, @Brian175 - -### Commits - -* [[`7370a62`](http://github.com/eggjs/egg/commit/7370a62e190db55dab3fde7f39f621f449301eaa)] - docs: translate tutorials/restful.md (#908) (Darren Wong <>) -* [[`5d8ca65`](http://github.com/eggjs/egg/commit/5d8ca654f311c52fd5faaa939943071c3f69f43f)] - docs: translatebasics/controller.md (#889) (lslxdx <>) -* [[`5b959e0`](http://github.com/eggjs/egg/commit/5b959e0a382491b3111afb66e10b6e866105e0c8)] - docs: translate tutorials/progressive.md to English version (#966) (Darren Wong <>) -* [[`35fa5a9c`](http://github.com/eggjs/egg/commit/35fa5a9c4c2d969f66a5e4df28e1da7f69370709)] - fix: set maxSockets defautl value to Number.MAX_SAFE_INTEGER (#938) (tangyao <<2001-wms@163.com>>) -* [[`5b6fe2b`](http://github.com/eggjs/egg/commit/5b6fe2b187b2c1a4bcee4693b2b1043f2724fe68)] - feat: use lru to aovid oom in dns cache httpclient (#961) (Yiyu He <>) -* [[`3c5c0b8`](http://github.com/eggjs/egg/commit/3c5c0b8d81bb63166f6592390d14277d3baca283)] - docs: Fix objects.md typo (#969) (三点 <>) -* [[`2bca50b`](http://github.com/eggjs/egg/commit/2bca50b2217424b8cdacd48550dcc39a31e50cff)] - docs(core/unittest.md): update with app.httpRequest() (#943) (Weilun Xiong <<330815461@qq.com>>) -* [[`713e033`](http://github.com/eggjs/egg/commit/713e033f90eb39aad8ac48916985396ca5282815)] - docs: app.controller.foo instead of 'foo' (#942) (Yiyu He <>) -* [[`cfc76ec`](http://github.com/eggjs/egg/commit/cfc76ec721460780d703ead1dfdd315ed484e5c8)] - fix spell error from sign to signed (#932) (johnnychen <>) -* [[`12499d6`](http://github.com/eggjs/egg/commit/12499d636dd471f35e54aad9f09b5f452ea198bf)] - docs: fix yield db.query for en (#930) (Yao Mengfei <>) -* [[`25c7c95`](http://github.com/eggjs/egg/commit/25c7c95bff9eb51baf4f93724444982209872895)] - docs: translate basics/router.md (#896) (lslxdx <>) -* [[`a5c7ac4`](http://github.com/eggjs/egg/commit/a5c7ac462a275c5393f93308a7f31b21cba524a2)] - docs: translate basics/service.md (lslxdx <>) -* [[`7ee5de6`](http://github.com/eggjs/egg/commit/7ee5de6b0ad628332a5c130eb5a405b993a98c60)] - docs: translate basics/extend.md (#884) (DanielLam <>) -* [[`9bf3a65`](http://github.com/eggjs/egg/commit/9bf3a6511469ee85963096836ae8c2421313448d)] - docs: Update env.md (#918) (m31271n <>) -* [[`b3825f3`](http://github.com/eggjs/egg/commit/b3825f33406c01ebc19b16519eccfca9f60e770f)] - docs: fix objects.md (#928) (Yiyu He <>) -* [[`fd04ea2`](http://github.com/eggjs/egg/commit/fd04ea222af962e7fe9b82d108a0bd6f23b32891)] - docs: add document for built-in objects (#914) (Yiyu He <>) -* [[`6180d5d`](http://github.com/eggjs/egg/commit/6180d5db90047a58222ba24d660c1a19b93648f3)] - docs: use names of constants declared (#923) (Yao Mengfei <>) -* [[`02b02e0`](http://github.com/eggjs/egg/commit/02b02e0faf0d423105136723b9d2938a182fd486)] - docs: using a doctools as a external lib (#913) (Haoliang Gao <>) -* [[`5113088`](http://github.com/eggjs/egg/commit/51130889ad8d75baa157c43d9b88e7d08c6067fe)] - fix(docs): yield db.query (#921) (Yao Mengfei <>) -* [[`ddd342c`](http://github.com/eggjs/egg/commit/ddd342c84358319aaffe9ee6eab90c2df1a2e9dc)] - docs: translate basic/config.md (#875) (Brian175 <>) -* [[`ae99e5d`](http://github.com/eggjs/egg/commit/ae99e5d6ee032171d17ce7ce67a8cb3c2f7bd04b)] - fix(docs): basics/structure.md link agent typo (#909) (Weilun Xiong <<330815461@qq.com>>) -* [[`fac3e0c`](http://github.com/eggjs/egg/commit/fac3e0c7306b1143698c29a3685c8116c36b1434)] - refactor: rename private method name to symbol (#904) (Yu Qi <>) -* [[`8115c57`](http://github.com/eggjs/egg/commit/8115c575ea082a92ebda5e4fd08ba4ad37e47bc0)] - docs: translate docs/source/zh-cn/tutorials/mysql.md (#883) (Darren Wong <>) -* [[`e13c515`](http://github.com/eggjs/egg/commit/e13c515226566ae3c87c35b575a8e914e75c6a0b)] - Release 1.3.0 (#885) (fengmk2 <>) +- **feature** + - use lru to aovid oom when httpclient dns cache enabled +- **fix** + - fix port is missed when httpclient dns cache enabled + - fix request url object will be changed when httpclient dns cache enabled + - set maxSockets defautl value to Number.MAX_SAFE_INTEGER +- **document** + - Documents improved. Thanks @DarrenWong, @zousandian, @lslxdx, @Azard, @johnnychen, @coogleyao, @DanielWLam, @m31271n, @Brian175 + +### Commits + +- [[`7370a62`](http://github.com/eggjs/egg/commit/7370a62e190db55dab3fde7f39f621f449301eaa)] - docs: translate tutorials/restful.md (#908) (Darren Wong <>) +- [[`5d8ca65`](http://github.com/eggjs/egg/commit/5d8ca654f311c52fd5faaa939943071c3f69f43f)] - docs: translatebasics/controller.md (#889) (lslxdx <>) +- [[`5b959e0`](http://github.com/eggjs/egg/commit/5b959e0a382491b3111afb66e10b6e866105e0c8)] - docs: translate tutorials/progressive.md to English version (#966) (Darren Wong <>) +- [[`35fa5a9c`](http://github.com/eggjs/egg/commit/35fa5a9c4c2d969f66a5e4df28e1da7f69370709)] - fix: set maxSockets defautl value to Number.MAX_SAFE_INTEGER (#938) (tangyao <<2001-wms@163.com>>) +- [[`5b6fe2b`](http://github.com/eggjs/egg/commit/5b6fe2b187b2c1a4bcee4693b2b1043f2724fe68)] - feat: use lru to aovid oom in dns cache httpclient (#961) (Yiyu He <>) +- [[`3c5c0b8`](http://github.com/eggjs/egg/commit/3c5c0b8d81bb63166f6592390d14277d3baca283)] - docs: Fix objects.md typo (#969) (三点 <>) +- [[`2bca50b`](http://github.com/eggjs/egg/commit/2bca50b2217424b8cdacd48550dcc39a31e50cff)] - docs(core/unittest.md): update with app.httpRequest() (#943) (Weilun Xiong <<330815461@qq.com>>) +- [[`713e033`](http://github.com/eggjs/egg/commit/713e033f90eb39aad8ac48916985396ca5282815)] - docs: app.controller.foo instead of 'foo' (#942) (Yiyu He <>) +- [[`cfc76ec`](http://github.com/eggjs/egg/commit/cfc76ec721460780d703ead1dfdd315ed484e5c8)] - fix spell error from sign to signed (#932) (johnnychen <>) +- [[`12499d6`](http://github.com/eggjs/egg/commit/12499d636dd471f35e54aad9f09b5f452ea198bf)] - docs: fix yield db.query for en (#930) (Yao Mengfei <>) +- [[`25c7c95`](http://github.com/eggjs/egg/commit/25c7c95bff9eb51baf4f93724444982209872895)] - docs: translate basics/router.md (#896) (lslxdx <>) +- [[`a5c7ac4`](http://github.com/eggjs/egg/commit/a5c7ac462a275c5393f93308a7f31b21cba524a2)] - docs: translate basics/service.md (lslxdx <>) +- [[`7ee5de6`](http://github.com/eggjs/egg/commit/7ee5de6b0ad628332a5c130eb5a405b993a98c60)] - docs: translate basics/extend.md (#884) (DanielLam <>) +- [[`9bf3a65`](http://github.com/eggjs/egg/commit/9bf3a6511469ee85963096836ae8c2421313448d)] - docs: Update env.md (#918) (m31271n <>) +- [[`b3825f3`](http://github.com/eggjs/egg/commit/b3825f33406c01ebc19b16519eccfca9f60e770f)] - docs: fix objects.md (#928) (Yiyu He <>) +- [[`fd04ea2`](http://github.com/eggjs/egg/commit/fd04ea222af962e7fe9b82d108a0bd6f23b32891)] - docs: add document for built-in objects (#914) (Yiyu He <>) +- [[`6180d5d`](http://github.com/eggjs/egg/commit/6180d5db90047a58222ba24d660c1a19b93648f3)] - docs: use names of constants declared (#923) (Yao Mengfei <>) +- [[`02b02e0`](http://github.com/eggjs/egg/commit/02b02e0faf0d423105136723b9d2938a182fd486)] - docs: using a doctools as a external lib (#913) (Haoliang Gao <>) +- [[`5113088`](http://github.com/eggjs/egg/commit/51130889ad8d75baa157c43d9b88e7d08c6067fe)] - fix(docs): yield db.query (#921) (Yao Mengfei <>) +- [[`ddd342c`](http://github.com/eggjs/egg/commit/ddd342c84358319aaffe9ee6eab90c2df1a2e9dc)] - docs: translate basic/config.md (#875) (Brian175 <>) +- [[`ae99e5d`](http://github.com/eggjs/egg/commit/ae99e5d6ee032171d17ce7ce67a8cb3c2f7bd04b)] - fix(docs): basics/structure.md link agent typo (#909) (Weilun Xiong <<330815461@qq.com>>) +- [[`fac3e0c`](http://github.com/eggjs/egg/commit/fac3e0c7306b1143698c29a3685c8116c36b1434)] - refactor: rename private method name to symbol (#904) (Yu Qi <>) +- [[`8115c57`](http://github.com/eggjs/egg/commit/8115c575ea082a92ebda5e4fd08ba4ad37e47bc0)] - docs: translate docs/source/zh-cn/tutorials/mysql.md (#883) (Darren Wong <>) +- [[`e13c515`](http://github.com/eggjs/egg/commit/e13c515226566ae3c87c35b575a8e914e75c6a0b)] - Release 1.3.0 (#885) (fengmk2 <>) ## 2017-05-11, Version 1.3.0, @fengmk2 ### Notable changes - * **document** - * Documents improved. Thanks @Rwing, @lslxdx, @solarhell, @magicdawn - * API document is out https://eggjs.org/api/ - * **refactor** - * Set coreLogger's consoleLevel to WARN in local env +- **document** + - Documents improved. Thanks @Rwing, @lslxdx, @solarhell, @magicdawn + - API document is out https://eggjs.org/api/ +- **refactor** + - Set coreLogger's consoleLevel to WARN in local env ### Commits - * [[`bd6681a`](http://github.com/eggjs/egg/commit/bd6681a509f74af7f39b1505962c0d75958ae0d3)] - chore: typo eggg=>egg (#881) (Rwing <>) - * [[`22c9cd9`](http://github.com/eggjs/egg/commit/22c9cd96df19bb43d1681ce0cffc59bc930c8f0f)] - docs: translated & proofread 'middleware.md' (#784) (lslxdx <>) - * [[`e55a134`](http://github.com/eggjs/egg/commit/e55a13439ec297081d33a7eb2f87ece605581908)] - docs: Add a link to issue template (#853) (Haoliang Gao <>) - * [[`b01d30e`](http://github.com/eggjs/egg/commit/b01d30e33e9b910ee24d69d3b55e2dbe887ff4e3)] - docs: Fix typo. (#869) (jethro <>) - * [[`b3403b5`](http://github.com/eggjs/egg/commit/b3403b56a5635394a4dc9825ef2780850449e573)] - docs: fix view typo (#867) (Tao <>) - * [[`5d6e067`](http://github.com/eggjs/egg/commit/5d6e067fc36697b7c01f290bccac06ce21fb4371)] - chore: add quality badge (#857) (仙森 <>) - * [[`8d6755b`](http://github.com/eggjs/egg/commit/8d6755b33c54d6230d1b20141dd6d043ed6c3897)] - deps: upgrade dependencies (#854) (Haoliang Gao <>) - * [[`bd0a827`](http://github.com/eggjs/egg/commit/bd0a827c38f0a2cff42c8a73909081a1f9cd939a)] - refactor: set consoleLevel WARN of coreLogger in local (#850) (Haoliang Gao <>) - * [[`af174ef`](http://github.com/eggjs/egg/commit/af174efb0a0dfe545849d03f8ec1fbee34559dae)] - docs: Add API document to menu (#845) (Haoliang Gao <>) - * [[`edfc07e`](http://github.com/eggjs/egg/commit/edfc07e841b751a4c195544167f50a2ad56971e8)] - chore: generate puml (#842) (Haoliang Gao <>) +- [[`bd6681a`](http://github.com/eggjs/egg/commit/bd6681a509f74af7f39b1505962c0d75958ae0d3)] - chore: typo eggg=>egg (#881) (Rwing <>) +- [[`22c9cd9`](http://github.com/eggjs/egg/commit/22c9cd96df19bb43d1681ce0cffc59bc930c8f0f)] - docs: translated & proofread 'middleware.md' (#784) (lslxdx <>) +- [[`e55a134`](http://github.com/eggjs/egg/commit/e55a13439ec297081d33a7eb2f87ece605581908)] - docs: Add a link to issue template (#853) (Haoliang Gao <>) +- [[`b01d30e`](http://github.com/eggjs/egg/commit/b01d30e33e9b910ee24d69d3b55e2dbe887ff4e3)] - docs: Fix typo. (#869) (jethro <>) +- [[`b3403b5`](http://github.com/eggjs/egg/commit/b3403b56a5635394a4dc9825ef2780850449e573)] - docs: fix view typo (#867) (Tao <>) +- [[`5d6e067`](http://github.com/eggjs/egg/commit/5d6e067fc36697b7c01f290bccac06ce21fb4371)] - chore: add quality badge (#857) (仙森 <>) +- [[`8d6755b`](http://github.com/eggjs/egg/commit/8d6755b33c54d6230d1b20141dd6d043ed6c3897)] - deps: upgrade dependencies (#854) (Haoliang Gao <>) +- [[`bd0a827`](http://github.com/eggjs/egg/commit/bd0a827c38f0a2cff42c8a73909081a1f9cd939a)] - refactor: set consoleLevel WARN of coreLogger in local (#850) (Haoliang Gao <>) +- [[`af174ef`](http://github.com/eggjs/egg/commit/af174efb0a0dfe545849d03f8ec1fbee34559dae)] - docs: Add API document to menu (#845) (Haoliang Gao <>) +- [[`edfc07e`](http://github.com/eggjs/egg/commit/edfc07e841b751a4c195544167f50a2ad56971e8)] - chore: generate puml (#842) (Haoliang Gao <>) ## 2017-05-04, Version 1.2.1, @popomore ### Notable changes - * **fix** - * loadPlugin can be extended +- **fix** + - loadPlugin can be extended ### Commits - * [[`13587667`](http://github.com/eggjs/egg/commit/13587667ac019ca516ae11aea728e84966dc57a5)] - fix(loader): loadPlugin can be extended (#836) (Haoliang Gao <>) - * [[`1a027ad7`](http://github.com/eggjs/egg/commit/1a027ad727468d48afe45d1f3ce54de2e4ecfd16)] - test: use assert instead of should (#837) (Haoliang Gao <>) - * [[`89b4df9d`](http://github.com/eggjs/egg/commit/89b4df9d21ddf07efd246145c52141a72e07ad80)] - docs: fix wrong name in chinese router doc (#833) (Tomatoo <<424203705@qq.com>>) +- [[`13587667`](http://github.com/eggjs/egg/commit/13587667ac019ca516ae11aea728e84966dc57a5)] - fix(loader): loadPlugin can be extended (#836) (Haoliang Gao <>) +- [[`1a027ad7`](http://github.com/eggjs/egg/commit/1a027ad727468d48afe45d1f3ce54de2e4ecfd16)] - test: use assert instead of should (#837) (Haoliang Gao <>) +- [[`89b4df9d`](http://github.com/eggjs/egg/commit/89b4df9d21ddf07efd246145c52141a72e07ad80)] - docs: fix wrong name in chinese router doc (#833) (Tomatoo <<424203705@qq.com>>) ## 2017-04-28, Version 1.2.0, @popomore ### Notable changes - * **document** - * Documents improved, Thanks @Rwing, @bingqichen, @okoala, @binsee, @lslxdx - * **feature** - * Move BaseContextClass to egg and add BaseContextLogger [#816](https://github.com/eggjs/egg/pull/816) - * Remove logger config in local environment [#695](https://github.com/eggjs/egg/pull/695) - -### Commits - - * [[`0757655c`](http://github.com/eggjs/egg/commit/0757655cfed451ab3b1ca5a480fb96a3da908708)] - feat: BaseContextClass add logger (#816) (Yiyu He <>) - * [[`9871e450`](http://github.com/eggjs/egg/commit/9871e45098ab4927236382656c4ac774eeffcd11)] - docs: only use inspect at 7.x+ (#813) (TZ | 天猪 <>) - * [[`394bf371`](http://github.com/eggjs/egg/commit/394bf3711312f09d851be728b718e4d0f8fc9c1f)] - docs:Modify some words (#811) (binsee <>) - * [[`1132779c`](http://github.com/eggjs/egg/commit/1132779c4057bf96be1b73a3473b1545c3b5ab7a)] - docs(head.swig):fix the document page anchor position offset. (#790) (binsee <>) - * [[`9ef9d6aa`](http://github.com/eggjs/egg/commit/9ef9d6aa5953106555f11ac5dee6fe544773ceb8)] - fix(package.json & doc.js): fix doc tool error. (#791) (binsee <>) - * [[`90234efb`](http://github.com/eggjs/egg/commit/90234efbae13066ced3d25e8ba7201c0197c3ab1)] - docs(middleware.md): fix grammar (lslxdx <>) - * [[`9200a51d`](http://github.com/eggjs/egg/commit/9200a51d5b5c530a8f5ce8af4dd61f38981dc4c8)] - docs(basic/controller.md): typo 'matchs' -> 'matches' (#802) (lslxdx <>) - * [[`b4eb05b3`](http://github.com/eggjs/egg/commit/b4eb05b301bb1226edfc634ec90d1a5ae53514e2)] - docs(zh-cn docs):fix some link and link text in docs (#789) (binsee <>) - * [[`df1bf345`](http://github.com/eggjs/egg/commit/df1bf3459fd03f948532f7b6d2d436a74c54ed59)] - docs: add inspector protocol vscode debug (#776) (仙森 <>) - * [[`a8893f7e`](http://github.com/eggjs/egg/commit/a8893f7e7d9937d675d8be0da7bed0f2c259ae39)] - docs: add vscode debug (#751) (#767) (仙森 <>) - * [[`d4c345d3`](http://github.com/eggjs/egg/commit/d4c345d3d29266e0eb248eecee27bc0e492f5e5e)] - docs: typo fix "aync => async" (BingqiChen <>) - * [[`492c97d6`](http://github.com/eggjs/egg/commit/492c97d61c75911ae0e987f65325a5c7493f63b9)] - docs: add vscode plugin link (#756) (TZ | 天猪 <>) - * [[`2bf23fef`](http://github.com/eggjs/egg/commit/2bf23feffb7b9ff1bc07d072a4052eec863d001c)] - docs: link plugins to github search results (#755) (Yiyu He <>) - * [[`5befb0b1`](http://github.com/eggjs/egg/commit/5befb0b1f0f525ba778d54a5dedb72f2e880ab60)] - feat: remove egg logger local config (#695) (TZ | 天猪 <>) - * [[`1ab42e02`](http://github.com/eggjs/egg/commit/1ab42e0243354eab7f602faebd76d7117038e877)] - docs: document for middleware order (#724) (Haoliang Gao <>) - * [[`d6be9499`](http://github.com/eggjs/egg/commit/d6be949973002880a2fe71313c7630f7f94fde97)] - chore: remove chinese commnets (#749) (Yiyu He <>) - * [[`3bdbcae2`](http://github.com/eggjs/egg/commit/3bdbcae2486073447849f6e09831860dc42995d6)] - docs: fix typo, egg-bin => egg-init (#747) (Rwing <>) +- **document** + - Documents improved, Thanks @Rwing, @bingqichen, @okoala, @binsee, @lslxdx +- **feature** + - Move BaseContextClass to egg and add BaseContextLogger [#816](https://github.com/eggjs/egg/pull/816) + - Remove logger config in local environment [#695](https://github.com/eggjs/egg/pull/695) + +### Commits + +- [[`0757655c`](http://github.com/eggjs/egg/commit/0757655cfed451ab3b1ca5a480fb96a3da908708)] - feat: BaseContextClass add logger (#816) (Yiyu He <>) +- [[`9871e450`](http://github.com/eggjs/egg/commit/9871e45098ab4927236382656c4ac774eeffcd11)] - docs: only use inspect at 7.x+ (#813) (TZ | 天猪 <>) +- [[`394bf371`](http://github.com/eggjs/egg/commit/394bf3711312f09d851be728b718e4d0f8fc9c1f)] - docs:Modify some words (#811) (binsee <>) +- [[`1132779c`](http://github.com/eggjs/egg/commit/1132779c4057bf96be1b73a3473b1545c3b5ab7a)] - docs(head.swig):fix the document page anchor position offset. (#790) (binsee <>) +- [[`9ef9d6aa`](http://github.com/eggjs/egg/commit/9ef9d6aa5953106555f11ac5dee6fe544773ceb8)] - fix(package.json & doc.js): fix doc tool error. (#791) (binsee <>) +- [[`90234efb`](http://github.com/eggjs/egg/commit/90234efbae13066ced3d25e8ba7201c0197c3ab1)] - docs(middleware.md): fix grammar (lslxdx <>) +- [[`9200a51d`](http://github.com/eggjs/egg/commit/9200a51d5b5c530a8f5ce8af4dd61f38981dc4c8)] - docs(basic/controller.md): typo 'matchs' -> 'matches' (#802) (lslxdx <>) +- [[`b4eb05b3`](http://github.com/eggjs/egg/commit/b4eb05b301bb1226edfc634ec90d1a5ae53514e2)] - docs(zh-cn docs):fix some link and link text in docs (#789) (binsee <>) +- [[`df1bf345`](http://github.com/eggjs/egg/commit/df1bf3459fd03f948532f7b6d2d436a74c54ed59)] - docs: add inspector protocol vscode debug (#776) (仙森 <>) +- [[`a8893f7e`](http://github.com/eggjs/egg/commit/a8893f7e7d9937d675d8be0da7bed0f2c259ae39)] - docs: add vscode debug (#751) (#767) (仙森 <>) +- [[`d4c345d3`](http://github.com/eggjs/egg/commit/d4c345d3d29266e0eb248eecee27bc0e492f5e5e)] - docs: typo fix "aync => async" (BingqiChen <>) +- [[`492c97d6`](http://github.com/eggjs/egg/commit/492c97d61c75911ae0e987f65325a5c7493f63b9)] - docs: add vscode plugin link (#756) (TZ | 天猪 <>) +- [[`2bf23fef`](http://github.com/eggjs/egg/commit/2bf23feffb7b9ff1bc07d072a4052eec863d001c)] - docs: link plugins to github search results (#755) (Yiyu He <>) +- [[`5befb0b1`](http://github.com/eggjs/egg/commit/5befb0b1f0f525ba778d54a5dedb72f2e880ab60)] - feat: remove egg logger local config (#695) (TZ | 天猪 <>) +- [[`1ab42e02`](http://github.com/eggjs/egg/commit/1ab42e0243354eab7f602faebd76d7117038e877)] - docs: document for middleware order (#724) (Haoliang Gao <>) +- [[`d6be9499`](http://github.com/eggjs/egg/commit/d6be949973002880a2fe71313c7630f7f94fde97)] - chore: remove chinese commnets (#749) (Yiyu He <>) +- [[`3bdbcae2`](http://github.com/eggjs/egg/commit/3bdbcae2486073447849f6e09831860dc42995d6)] - docs: fix typo, egg-bin => egg-init (#747) (Rwing <>) ## 2017-04-11, Version 1.1.0, @fengmk2 ### Notable changes - * **document** - * Lots of documents improve and typo fixes. Thanks @lslxdx, @zhennann, @dotnil, @no7dw, @cuyl, @Andiedie, @kylezhang, - @SF-Zhou, @yandongxu, @jemmyzheng, @Carrotzpc, @zbinlin, @OneNewLife, @monkindey, @simman, - @demohi, @xwang1024 and @davidnotes - * **feature** - * warn if some confused configurations exist in config [#637](https://github.com/eggjs/egg/pull/637) - * use extend2 instead of extend to support `Array` config value [#674](https://github.com/eggjs/egg/pull/674) - * expose context base classes on Application instance, make app or framework override context extend more easily [#737](https://github.com/eggjs/egg/pull/737) - * expose egg.Controller and egg.Service [#741](https://github.com/eggjs/egg/pull/741) - * **fix** - * remove unused `jsonp` context delegate to response, please use [jsonp middleware instead](https://eggjs.org/zh-cn/basics/controller.html#jsonp) [#739](https://github.com/eggjs/egg/pull/739) - -### Commits - - * [[`241b4e8`](http://github.com/eggjs/egg/commit/241b4e83c05e7086493564e536f5ce69d17dde0c)] - feat: expose egg.Controller and egg.Service (#741) (Yiyu He <>) - * [[`26efa42`](http://github.com/eggjs/egg/commit/26efa427cf34e0ef0482d69fc10a77280e5fea5e)] - fix: remove unused jsonp delegate (#739) (Yiyu He <>) - * [[`c33523d`](http://github.com/eggjs/egg/commit/c33523db3e086eafd1f7bc7486c6d1b2b68335e3)] - feat: export context base classes on Application (#737) (fengmk2 <>) - * [[`ee127ad`](http://github.com/eggjs/egg/commit/ee127ad46b33a19d43c84a04649569a404a7f6af)] - docs: add sub directory support for controller (#734) (Yiyu He <>) - * [[`88a1669`](http://github.com/eggjs/egg/commit/88a166933478373c4fd5cdd349d3b63e00cbaf7e)] - docs: typo at controller.md (#720) (lslxdx <>) - * [[`4c298c2`](http://github.com/eggjs/egg/commit/4c298c2c70017d12688e2801bfe6e66886ba24bd)] - docs: async-function typo, change generator to async (#712) (zhennann <>) - * [[`a9d27d0`](http://github.com/eggjs/egg/commit/a9d27d0ab3f3dea89487fc1e8c084b9ddc7e854d)] - docs: add schedule max interval (#711) (Yiyu He <>) - * [[`9e94b7b`](http://github.com/eggjs/egg/commit/9e94b7b31106ce578a67dd15984d847587527299)] - docs: little grammar issues (#707) (Chen Yangjian <>) - * [[`a4d12ec`](http://github.com/eggjs/egg/commit/a4d12ecc6c468ebf37ff6acba06e65b15cfde4f4)] - chore: remove unused config (#694) (Yiyu He <>) - * [[`88449f9`](http://github.com/eggjs/egg/commit/88449f9b292d69bd2f936f0ecb037efecbed2e8e)] - docs: add webstorm debug (#689) (TZ | 天猪 <>) - * [[`8517625`](http://github.com/eggjs/egg/commit/8517625b44f36909169032f8fff3ced3e1910a47)] - docs: correct spelling mistake (#682) (Wade Deng <>) - * [[`92ef92b`](http://github.com/eggjs/egg/commit/92ef92b7cec015d2843c9d7cb113694ad7ca34ec)] - docs: faq add where are my logs (#680) (Yiyu He <>) - * [[`b8fc4e4`](http://github.com/eggjs/egg/commit/b8fc4e460e2dcffe60364a71dec2d07bd354d2cf)] - deps: use extend2 instead of extend (#674) (Yiyu He <>) - * [[`0ccbcf9`](http://github.com/eggjs/egg/commit/0ccbcf98be8946891b520321743d3b5a95899955)] - docs: fix example code syntax error & typos (#672) (cuyl <<463060544@qq.com>>) - * [[`1486705`](http://github.com/eggjs/egg/commit/14867059b5070b274cbee26df3accf5463eb4fe8)] - docs: security match and ignore (#668) (Yiyu He <>) - * [[`7ab3791`](http://github.com/eggjs/egg/commit/7ab37915afc4a197cc58bc477e5b96cb1a73ced1)] - test: test for closing logger (#667) (Haoliang Gao <>) - * [[`5f5cf91`](http://github.com/eggjs/egg/commit/5f5cf91a6af118ebc558252e07bcfa0f094045e3)] - docs(quickstart): tip for controller and config style (#666) (TZ | 天猪 <>) - * [[`e47c24b`](http://github.com/eggjs/egg/commit/e47c24b3f1fd27b0f545f107913d6c6e1cae53ac)] - docs: fix example code typos (#629) (SF-Zhou <>) - * [[`7900576`](http://github.com/eggjs/egg/commit/7900576e690d038e4d75891890c467c743f03605)] - docs: fix egg-session-redis code (#642) (周长安 <>) - * [[`8c77e59`](http://github.com/eggjs/egg/commit/8c77e5907834cb110a99a4ace0356868107c88e6)] - feat: warn if some confused configurations exist in config (#637) (Yiyu He <>) - * [[`cd8c659`](http://github.com/eggjs/egg/commit/cd8c65965dc62fe7d45598450d6ef31ab344b878)] - docs: fix some typo (#638) (kyle <>) - * [[`7d830b7`](http://github.com/eggjs/egg/commit/7d830b7c92f81a9d133b7f1e6fe71b3d8a8d5a31)] - docs: fix reference framework path (#634) (kyle <>) - * [[`a471e93`](http://github.com/eggjs/egg/commit/a471e93977e67c98280af8517100bfe48495bbb2)] - docs: fix example code in basics/middleware (#624) (SF-Zhou <>) - * [[`e87c170`](http://github.com/eggjs/egg/commit/e87c170770c117d275fd84c02a9fb1e699fa94cf)] - docs: fix code syntax (#628) (dongxu <>) - * [[`531dadd`](http://github.com/eggjs/egg/commit/531dadd7c3f8bd813c365d705ce7293a719e98f3)] - docs(security): Cookie of token, the key must be csrfToken (#625) (jemmy zheng <>) - * [[`8d73b02`](http://github.com/eggjs/egg/commit/8d73b02dcb856e3d8075aa34bc47a2f6dbb3af2b)] - docs: move cnzz to layout (#622) (Haoliang Gao <>) - * [[`077bebe`](http://github.com/eggjs/egg/commit/077bebe17889d8a0cff2a1dbfebd72b4b8147ab3)] - docs: fix table render error in en env.md (#621) (SF-Zhou <>) - * [[`990d45e`](http://github.com/eggjs/egg/commit/990d45e75f2d73b9bb4cddbf76e67452740e3178)] - docs: fixed table render error in env.md (#619) (SF-Zhou <>) - * [[`e9428ba`](http://github.com/eggjs/egg/commit/e9428ba95fcd07ba255359a968dd027932ce2f77)] - docs: improve left padding when window between 1005 and 1130 (#617) (Haoliang Gao <>) - * [[`c22e005`](http://github.com/eggjs/egg/commit/c22e0055ca8df35c1aa9d7d6ed7e31c21dd4b547)] - docs: turn off safe write in Jetbrains softwares (#614) (Shawn <>) - * [[`2296b7b`](http://github.com/eggjs/egg/commit/2296b7b22cc3e240bb676444d4fd2f953338cea5)] - docs: fix document deploy (#609) (Haoliang Gao <>) +- **document** + - Lots of documents improve and typo fixes. Thanks @lslxdx, @zhennann, @dotnil, @no7dw, @cuyl, @Andiedie, @kylezhang, + @SF-Zhou, @yandongxu, @jemmyzheng, @Carrotzpc, @zbinlin, @OneNewLife, @monkindey, @simman, + @demohi, @xwang1024 and @davidnotes +- **feature** + - warn if some confused configurations exist in config [#637](https://github.com/eggjs/egg/pull/637) + - use extend2 instead of extend to support `Array` config value [#674](https://github.com/eggjs/egg/pull/674) + - expose context base classes on Application instance, make app or framework override context extend more easily [#737](https://github.com/eggjs/egg/pull/737) + - expose egg.Controller and egg.Service [#741](https://github.com/eggjs/egg/pull/741) +- **fix** + - remove unused `jsonp` context delegate to response, please use [jsonp middleware instead](https://eggjs.org/zh-cn/basics/controller.html#jsonp) [#739](https://github.com/eggjs/egg/pull/739) + +### Commits + +- [[`241b4e8`](http://github.com/eggjs/egg/commit/241b4e83c05e7086493564e536f5ce69d17dde0c)] - feat: expose egg.Controller and egg.Service (#741) (Yiyu He <>) +- [[`26efa42`](http://github.com/eggjs/egg/commit/26efa427cf34e0ef0482d69fc10a77280e5fea5e)] - fix: remove unused jsonp delegate (#739) (Yiyu He <>) +- [[`c33523d`](http://github.com/eggjs/egg/commit/c33523db3e086eafd1f7bc7486c6d1b2b68335e3)] - feat: export context base classes on Application (#737) (fengmk2 <>) +- [[`ee127ad`](http://github.com/eggjs/egg/commit/ee127ad46b33a19d43c84a04649569a404a7f6af)] - docs: add sub directory support for controller (#734) (Yiyu He <>) +- [[`88a1669`](http://github.com/eggjs/egg/commit/88a166933478373c4fd5cdd349d3b63e00cbaf7e)] - docs: typo at controller.md (#720) (lslxdx <>) +- [[`4c298c2`](http://github.com/eggjs/egg/commit/4c298c2c70017d12688e2801bfe6e66886ba24bd)] - docs: async-function typo, change generator to async (#712) (zhennann <>) +- [[`a9d27d0`](http://github.com/eggjs/egg/commit/a9d27d0ab3f3dea89487fc1e8c084b9ddc7e854d)] - docs: add schedule max interval (#711) (Yiyu He <>) +- [[`9e94b7b`](http://github.com/eggjs/egg/commit/9e94b7b31106ce578a67dd15984d847587527299)] - docs: little grammar issues (#707) (Chen Yangjian <>) +- [[`a4d12ec`](http://github.com/eggjs/egg/commit/a4d12ecc6c468ebf37ff6acba06e65b15cfde4f4)] - chore: remove unused config (#694) (Yiyu He <>) +- [[`88449f9`](http://github.com/eggjs/egg/commit/88449f9b292d69bd2f936f0ecb037efecbed2e8e)] - docs: add webstorm debug (#689) (TZ | 天猪 <>) +- [[`8517625`](http://github.com/eggjs/egg/commit/8517625b44f36909169032f8fff3ced3e1910a47)] - docs: correct spelling mistake (#682) (Wade Deng <>) +- [[`92ef92b`](http://github.com/eggjs/egg/commit/92ef92b7cec015d2843c9d7cb113694ad7ca34ec)] - docs: faq add where are my logs (#680) (Yiyu He <>) +- [[`b8fc4e4`](http://github.com/eggjs/egg/commit/b8fc4e460e2dcffe60364a71dec2d07bd354d2cf)] - deps: use extend2 instead of extend (#674) (Yiyu He <>) +- [[`0ccbcf9`](http://github.com/eggjs/egg/commit/0ccbcf98be8946891b520321743d3b5a95899955)] - docs: fix example code syntax error & typos (#672) (cuyl <<463060544@qq.com>>) +- [[`1486705`](http://github.com/eggjs/egg/commit/14867059b5070b274cbee26df3accf5463eb4fe8)] - docs: security match and ignore (#668) (Yiyu He <>) +- [[`7ab3791`](http://github.com/eggjs/egg/commit/7ab37915afc4a197cc58bc477e5b96cb1a73ced1)] - test: test for closing logger (#667) (Haoliang Gao <>) +- [[`5f5cf91`](http://github.com/eggjs/egg/commit/5f5cf91a6af118ebc558252e07bcfa0f094045e3)] - docs(quickstart): tip for controller and config style (#666) (TZ | 天猪 <>) +- [[`e47c24b`](http://github.com/eggjs/egg/commit/e47c24b3f1fd27b0f545f107913d6c6e1cae53ac)] - docs: fix example code typos (#629) (SF-Zhou <>) +- [[`7900576`](http://github.com/eggjs/egg/commit/7900576e690d038e4d75891890c467c743f03605)] - docs: fix egg-session-redis code (#642) (周长安 <>) +- [[`8c77e59`](http://github.com/eggjs/egg/commit/8c77e5907834cb110a99a4ace0356868107c88e6)] - feat: warn if some confused configurations exist in config (#637) (Yiyu He <>) +- [[`cd8c659`](http://github.com/eggjs/egg/commit/cd8c65965dc62fe7d45598450d6ef31ab344b878)] - docs: fix some typo (#638) (kyle <>) +- [[`7d830b7`](http://github.com/eggjs/egg/commit/7d830b7c92f81a9d133b7f1e6fe71b3d8a8d5a31)] - docs: fix reference framework path (#634) (kyle <>) +- [[`a471e93`](http://github.com/eggjs/egg/commit/a471e93977e67c98280af8517100bfe48495bbb2)] - docs: fix example code in basics/middleware (#624) (SF-Zhou <>) +- [[`e87c170`](http://github.com/eggjs/egg/commit/e87c170770c117d275fd84c02a9fb1e699fa94cf)] - docs: fix code syntax (#628) (dongxu <>) +- [[`531dadd`](http://github.com/eggjs/egg/commit/531dadd7c3f8bd813c365d705ce7293a719e98f3)] - docs(security): Cookie of token, the key must be csrfToken (#625) (jemmy zheng <>) +- [[`8d73b02`](http://github.com/eggjs/egg/commit/8d73b02dcb856e3d8075aa34bc47a2f6dbb3af2b)] - docs: move cnzz to layout (#622) (Haoliang Gao <>) +- [[`077bebe`](http://github.com/eggjs/egg/commit/077bebe17889d8a0cff2a1dbfebd72b4b8147ab3)] - docs: fix table render error in en env.md (#621) (SF-Zhou <>) +- [[`990d45e`](http://github.com/eggjs/egg/commit/990d45e75f2d73b9bb4cddbf76e67452740e3178)] - docs: fixed table render error in env.md (#619) (SF-Zhou <>) +- [[`e9428ba`](http://github.com/eggjs/egg/commit/e9428ba95fcd07ba255359a968dd027932ce2f77)] - docs: improve left padding when window between 1005 and 1130 (#617) (Haoliang Gao <>) +- [[`c22e005`](http://github.com/eggjs/egg/commit/c22e0055ca8df35c1aa9d7d6ed7e31c21dd4b547)] - docs: turn off safe write in Jetbrains softwares (#614) (Shawn <>) +- [[`2296b7b`](http://github.com/eggjs/egg/commit/2296b7b22cc3e240bb676444d4fd2f953338cea5)] - docs: fix document deploy (#609) (Haoliang Gao <>) ## 2017-03-21, Version 1.0.0, @popomore @@ -2084,352 +2054,328 @@ Release the first stable version :egg: :clap::clap::clap: ### Commits - * [[`a3ad38d`](http://github.com/eggjs/egg/commit/a3ad38d649ff8eb0cd6dfcbe338466f1c59afef3)] - docs: fix HttpClient link in docs (#599) (Luobo Zhang <>) - * [[`242a4a1`](http://github.com/eggjs/egg/commit/242a4a1fbecfc4efa37cca58d1861040dd5838bd)] - docs: fix session's maxage (#598) (Yiyu He <>) - * [[`ee77e5c`](http://github.com/eggjs/egg/commit/ee77e5cdcb444f86bf9f50bfd89a63dd9321449f)] - docs: fix some typo (#597) (kyle <>) - * [[`984d732`](http://github.com/eggjs/egg/commit/984d7320881adf9420e5c7e49d62d5530ad887dd)] - refactor: app.cluster auto bind this (#570) (zōng yǔ <>) - * [[`4687f0f`](http://github.com/eggjs/egg/commit/4687f0f47566373938f9f928ac1dc4fa62590f4d)] - docs: fix session link (#595) (TZ | 天猪 <>) - * [[`3849c1c`](http://github.com/eggjs/egg/commit/3849c1c4b8f0354b12fd17bb884c33ef9e115e3c)] - docs: fix typo of httpclient & unittest (#591) (kyle <>) - * [[`871aa82`](http://github.com/eggjs/egg/commit/871aa82d28eeb026de6633cafbe168cca8ad3182)] - docs: add gitter & more controller ctx style (#585) (TZ | 天猪 <>) - * [[`a172960`](http://github.com/eggjs/egg/commit/a1729604959af84878dddb2776d621ee01c2d447)] - docs: typo (kyle <>) - * [[`54c10bc`](http://github.com/eggjs/egg/commit/54c10bc085b380f4f003d2f7987c205264dde1ad)] - docs: change controller showcase style to ctx (#568) (TZ | 天猪 <>) - * [[`d131f23`](http://github.com/eggjs/egg/commit/d131f236111981d7fb7021998bed200a46a4603d)] - docs: fix typo in docs (#563) (Jason Lee <>) - * [[`497b9a9`](http://github.com/eggjs/egg/commit/497b9a9e7c5cdcb0b769691ea40a74a4d284cfff)] - docs(faq): fix cluster link (#557) (Mars Wong <>) - * [[`0d37e42`](http://github.com/eggjs/egg/commit/0d37e42259647ce9cb43deeba7a887817c7ef408)] - docs: update the style for search (#558) (TZ | 天猪 <>) - * [[`24ef44f`](http://github.com/eggjs/egg/commit/24ef44fa662392c7b80dbba8da0c4d5a7c9b83dd)] - docs: fix typo (#565) (Colin Cheng <>) - * [[`9eecf7b`](http://github.com/eggjs/egg/commit/9eecf7b0f928fc33d47e93782c79289ca2a13289)] - docs: rule for transforming filepath to properties (#547) (Haoliang Gao <>) - * [[`d088283`](http://github.com/eggjs/egg/commit/d0882837c34a8b950a11e4f8fe4f47f29d8823f7)] - feat: show warning message with call stack (#549) (fengmk2 <>) - * [[`4a89c3b`](http://github.com/eggjs/egg/commit/4a89c3b563ef79f5ad557ef741c16f283c11e835)] - docs: replace customEgg to framework (#545) (fengmk2 <>) - * [[`c1464fb`](http://github.com/eggjs/egg/commit/c1464fbecb27caa0dc6766147d3b13d790466386)] - docs: more detail for mysql dynamic create (#540) (TZ | 天猪 <>) - -1.0.0-rc.3 / 2017-03-10 -======================= - - * docs: fix doc scroll bug (#532) - * test: fix development test (#546) - * doc: add Algolia docsearch (#542) - * feat: [BREAKING_CHANGE] override array when load config (#522) - * docs: fix cookie example (#533) - * feat: ignore types when dump (#518) - * docs: rotate csrf token (#520) - * refactor: [BREAKING CHANGE] remove userservice and userrole (#527) - * refactor: [BREAKING_CHANGE] remove default validate plugin (#526) - * docs: fix doc build (#524) - * docs: fix middleware typo (#519) - * docs(quickstart): fix keys again (#515) - * docs(quickstart): fix keys (#511) - * docs: add cookie and session (#510) - * docs: fix html closing tag in quickstart (#512) - * docs: quickstart tip (#502) - * docs: add English version of `egg and koa` (#490) - * feat: remove default customEgg (#487) - * doc: add the view config for the egg-view-nunjucks (#496) - * test: add qs security test cases (#491) - * docs: remove meaningless word (#488) - -1.0.0-rc.2 / 2017-03-01 -======================= - - * deps: upgrade egg-session@2 to support external session store (#480) - * docs: fix view plugin config at quickstart (#482) - * docs: update document for view that using egg-view (#475) - * docs: add config merge to faq (#478) - * docs(doc): add english version of "what is egg" (#462) - * docs: fix deployment link (#473) - * docs: add document for deployment (#448) - * test: travis test on node 8 using nightly building (#464) - * docs: seperate cluster-and-ipc and cluster-client (#441) - * docs: fixed typos 'BS' (#461) - * docs: fixed spelling mistake (#460) - * test: disable error log to stderr (#453) - * docs: fix async-function demo link (#457) - * feat: throw if config.keys not exists when access app.keys (#443) - * docs: add year to licence && mysql docs (#447) - * feat: extend runInBackground on application (#442) - -1.0.0-rc.1 / 2017-02-23 -======================= - - * feat: [BREAKING_CHANGE] reimplement view, use egg-view plugin (#402) - * fix: listen CookieLimitExceed in app (#429) - * fix: close gracefully (#419) - * docs: correct spelling mistake (#424) - * feat: log error when cookie value's length exceed the limit (#418) - * docs: Update mysql.md (#422) - * docs: add more complete example code for quickstart (#412) - * fix: deprecate warning when inspect & toJSON (#408) - * docs: should listen egg-ready using messenger (#406) - * docs: correct english description at README (#400) - * docs: fix character type error and link reference error (#396) - * docs: add csrf to faq (#393) - * fix: keep unhandledRejectionError err object stack (#390) - * docs: use compress replace bodyparser for example (#391) - * docs: add directory structure (#383) - * docs: add api-doc (#369) - * docs: how to use koa's middleware (#386) - * feat: dump config both after loaded and ready (#377) - * docs: fix filename in config.md (#376) - * docs: add plugin dep name description (#374) - * docs: update version automatically (#367) - * doc: add pm2 faq (#370) - * docs: fix jsonp config in controller.md (#372) - * feat: [BREAKING_CHANGE] remove notfound.enableRedirect (#368) - * docs: add resource page (#364) - * docs: add config result description (#365) - * deps: upgrade egg-mock (#362) - * docs: english wip description & remove unuse file (#361) - * docs: add tutorials index & fix async (#359) - -0.12.0 / 2017-02-12 -=================== - - * docs: fix async link (#357) - * docs: add async await (#349) - * docs: typo Github > GitHub (#356) - * docs: update site style (#340) - * deps: upgrade egg-core (#350) - * docs: add description to config/env file (#348) - * docs: add APIClient concept to cluster doc (#344) - * test: add async test case (#339) - * feat: view base promise to support async function (#343) - * feat: curl return promise (#342) - * test: add class style controller tests (#336) - * docs: add cnzz (#335) - * test: improve coverage to 100% (#333) - * docs: update egg-and-koa with async function (#334) - * fix: remove tair and hsf (#332) - * docs: quickstart - use controller class (#329) - -0.11.0 / 2017-02-07 -=================== - - * feat: remove overrideMethod middleware (#324) - * feat: remove worker client, use app.cluster (#282) - * chore(scripts): Add PATH to find hexo (#327) - * docs: fix quickstart example code (#326) - * chore(scripts): deploy document by travis (#325) - * docs: add httpclient tracer demo and docs (#313) - * feat: close cluster clients before app close (#310) - * test: mv benchmark to eggjs/benchmark (#320) - * docs: document for plugin.{env}.js and the reason of plugin name (#321) - * docs: add sigleton in plugin.md (#316) - * docs: plugin and framework list use github tags (#318) - * docs: remove outdated docs (#319) - * docs: controller support class and refactor jsonp (#314) - * docs: add more details about csrf (#315) - -0.10.0 / 2017-02-03 -=================== - - * feat: remove tracer (#311) - * refactor: use app.beforeClose (#306) - * feat: move ctx.runtime to egg-instrument (#302) - * feat: merge the api of application/agent from extend to instance (#294) - * docs: add egg-security config to router docs (#303) - * style: fix code style for app and config (#300) - * refactor: remove ctx.jsonp and add egg-jsonp plugin (#299) - * docs: fix typo $app to app (#297) - * docs: remove inner links (#298) - -0.9.0 / 2017-01-22 -================== - - * feat: remove isAjax (#295) - * test: fix cookie test cases (#296) - * docs: adjust some words (#291) - * feat: move clusterPort to egg-cluster (#281) - * feat: move app.Service egg-core (#279) - * docs: change egg-bin to egg-init (#284) - * docs: improve framework doc based on eggjs/examples#9 (#267) - * feat: remove instrument (#283) - * docs: add progressive link && adjust en docs directory (#275) - * docs: add progressive usage (#268) - -0.8.0 / 2017-01-18 -================== - - * test: dep -> dependencies (#270) - * docs: translate zh-cn/basics/app-start.md into english (#222) - * docs: fix quickstart typo (#266) - * docs: add http client debug docs (#265) - * docs: modify and fix 3 points (#264) - * docs(intro): improve decription (#263) - * docs: fix docs site version (#262) - * docs: Fix typo. (#261) - * docs: review 1st version docs (#257) - * fix: typo conext -> context (#259) - * docs: contributing && readme && deps (#253) - * docs: fix quickstart link in index.html (#256) - * docs: set the default locale zh-cn (#255) - * refactor: ctx.realStatus delegate ctx.response.realStatus (#252) - * docs: Add intro/index.md (#246) - * feat: adjust default plugins (#251) - * docs: add RESTful documents (#247) - * feat: delegate ctx.jsonp to ctx.response.jsonp (#248) - * chore: remove examples (#245) - * docs: improve mysql doc - * docs: add mysql doc - * docs: view (#228) - * docs: improve doc theme (#230) - * docs: add core/unittest.md (#199) - * docs: add advanced/framework.md (#225) - -0.7.0 / 2017-01-12 -================== - - * docs: add service doc (#221) - * docs: serverEnv => env (#239) - * feat: delegate configurations in app (#233) - * refactor: remove ctx.getCookie, ctx.setCookie and ctx.deleteCookie (#240) - * docs: remove mon-printable character (#242) - * feat: support app.config.proxy to identify app is behind a proxy (#231) - * doc: add plugin doc (#224) - * docs: add Quick Start in English (#223) - * docs: add basics/controller.md (#209) - * docs: add core/development.md (#214) - * docs: remove init.js from document, use app.beforeStart (#229) - * docs: quickstart (#217) - * docs: add security plugin doc (#196) - * docs: mv cluster.md to zh-cn (#216) - * feat: add cluster-client (#191) - * docs: add basics/router.md (#203) - * docs: add advanced/loader.md (#198) - * docs: fix i18n doc (#210) - * docs: add core/i18n.md (#208) - * docs: add core/httpclient document (#197) - * docs: typo (#207) - * docs: add core/logger.md (#204) - * docs: add one more reason why not use koa 2 (#206) - * docs: add error handling (#205) - * docs: add schedule (#202) - * docs: add english translation of basics/env.md - * docs: basics/middleware (#194) - * docs: add basics/config.md (#188) - * doc: app start (#193) - * docs: rename koa.md to egg-and-koa.md (#190) - * docs: egg and koa (#179) - * doc: add basics/env.md (#178) - * doc: rename guide/basics/extend.md to basics/extend.md (#189) - * doc: guide/basics/extend doc (#187) - -0.6.3 / 2016-12-30 -================== - - * refactor: use logger.close, .end is deprecated (#171) - -0.6.2 / 2016-12-22 -================== - - * refactor(config): set keepAliveTimeout 4000ms by default (#165) - -0.6.1 / 2016-12-21 -================== - - * refactor: use sendToApp/sendToAgent in worker client - * fix: protocolHeaders can split with whitespace (#164) - * deps: update version (#157) - -0.6.0 / 2016-12-03 -================== - - * deps: egg-cookies@2 (#155) - * fix: already supported in egg-core (#154) - * feat: body parser support disable, ignore and match (#150) - * feat: use appInfo.root in config (#147) - * test: refactor workclient test cases (#145) - * feat: add a dns cache httpclient (#146) - -0.5.0 / 2016-11-04 -================== - - * deps: upgrade dependencies (#144) - * feat: warn when agent send message before started (#143) - * feat: [BREAKING_CHANGE] refactor Messenger (#141) - * feat: print error to console on unittest env (#139) - * feat: add ip setter on request (#138) - * feat: add getLogger to app and ctx (#136) - * test: remove co-sleep deps - * test: add local server for curl test cases - * test: use fs read instead of curl test on runInBackground - -0.4.0 / 2016-10-29 -================== - - * deps: update version (#135) - * feat: support background task on ctx (#119) - * chore: add middleware example (#121) - -0.3.0 / 2016-10-28 -================== - - * test: fix unstable test (#133) - * feat: close return promise (#128) - * deps: update deps version (#113) - * fix: AppWorkerClient subscribe same data failed issue (#110) - -0.2.1 / 2016-09-16 -================== - - * feat(application): emit startTimeout event (#107) - * perf: get header using lower case (#106) - * chore: remove --fix for error check but not fix (#101) - * doc: Add Installation (#95) - * doc: add title (#94) - -0.2.0 / 2016-09-03 -================== - - * docs: improve documents - * test: update benchmark scripts (#79) - * test: add router for bench cases (#78) - * fix: set header use lowercase (#76) - * test: add toa benchmark (#75) - * test: add benchmark results (#74) - * test: fix security tests (#73) - * test: egg-view-nunjucks change views -> view (#72) - -0.1.3 / 2016-08-31 -================== - - * fix: utils.assign support undefined (#71) - * refactor: change accept to getter (#68) - -0.1.2 / 2016-08-31 -================== - - * deps: egg-security@1 (#67) - * Revert raw header (#65) - * feat: [BREAKING_CHANGE] remove poweredBy && config.core (#63) - -0.1.1 / 2016-08-29 -================== - - * refactor: use ctx.setRawHeader (#61) - * chore: add benchmarks (#62) - * fix(meta): remove server-id (#56) - * feat(response): add res.setRawHeader (#60) - * refator: use utils.assign instead of Object.assign (#59) - * feat: docs structure (#55) - * docs: web.md and web.zh_CN.md (#54) +- [[`a3ad38d`](http://github.com/eggjs/egg/commit/a3ad38d649ff8eb0cd6dfcbe338466f1c59afef3)] - docs: fix HttpClient link in docs (#599) (Luobo Zhang <>) +- [[`242a4a1`](http://github.com/eggjs/egg/commit/242a4a1fbecfc4efa37cca58d1861040dd5838bd)] - docs: fix session's maxage (#598) (Yiyu He <>) +- [[`ee77e5c`](http://github.com/eggjs/egg/commit/ee77e5cdcb444f86bf9f50bfd89a63dd9321449f)] - docs: fix some typo (#597) (kyle <>) +- [[`984d732`](http://github.com/eggjs/egg/commit/984d7320881adf9420e5c7e49d62d5530ad887dd)] - refactor: app.cluster auto bind this (#570) (zōng yǔ <>) +- [[`4687f0f`](http://github.com/eggjs/egg/commit/4687f0f47566373938f9f928ac1dc4fa62590f4d)] - docs: fix session link (#595) (TZ | 天猪 <>) +- [[`3849c1c`](http://github.com/eggjs/egg/commit/3849c1c4b8f0354b12fd17bb884c33ef9e115e3c)] - docs: fix typo of httpclient & unittest (#591) (kyle <>) +- [[`871aa82`](http://github.com/eggjs/egg/commit/871aa82d28eeb026de6633cafbe168cca8ad3182)] - docs: add gitter & more controller ctx style (#585) (TZ | 天猪 <>) +- [[`a172960`](http://github.com/eggjs/egg/commit/a1729604959af84878dddb2776d621ee01c2d447)] - docs: typo (kyle <>) +- [[`54c10bc`](http://github.com/eggjs/egg/commit/54c10bc085b380f4f003d2f7987c205264dde1ad)] - docs: change controller showcase style to ctx (#568) (TZ | 天猪 <>) +- [[`d131f23`](http://github.com/eggjs/egg/commit/d131f236111981d7fb7021998bed200a46a4603d)] - docs: fix typo in docs (#563) (Jason Lee <>) +- [[`497b9a9`](http://github.com/eggjs/egg/commit/497b9a9e7c5cdcb0b769691ea40a74a4d284cfff)] - docs(faq): fix cluster link (#557) (Mars Wong <>) +- [[`0d37e42`](http://github.com/eggjs/egg/commit/0d37e42259647ce9cb43deeba7a887817c7ef408)] - docs: update the style for search (#558) (TZ | 天猪 <>) +- [[`24ef44f`](http://github.com/eggjs/egg/commit/24ef44fa662392c7b80dbba8da0c4d5a7c9b83dd)] - docs: fix typo (#565) (Colin Cheng <>) +- [[`9eecf7b`](http://github.com/eggjs/egg/commit/9eecf7b0f928fc33d47e93782c79289ca2a13289)] - docs: rule for transforming filepath to properties (#547) (Haoliang Gao <>) +- [[`d088283`](http://github.com/eggjs/egg/commit/d0882837c34a8b950a11e4f8fe4f47f29d8823f7)] - feat: show warning message with call stack (#549) (fengmk2 <>) +- [[`4a89c3b`](http://github.com/eggjs/egg/commit/4a89c3b563ef79f5ad557ef741c16f283c11e835)] - docs: replace customEgg to framework (#545) (fengmk2 <>) +- [[`c1464fb`](http://github.com/eggjs/egg/commit/c1464fbecb27caa0dc6766147d3b13d790466386)] - docs: more detail for mysql dynamic create (#540) (TZ | 天猪 <>) + +# 1.0.0-rc.3 / 2017-03-10 + +- docs: fix doc scroll bug (#532) +- test: fix development test (#546) +- doc: add Algolia docsearch (#542) +- feat: [BREAKING_CHANGE] override array when load config (#522) +- docs: fix cookie example (#533) +- feat: ignore types when dump (#518) +- docs: rotate csrf token (#520) +- refactor: [BREAKING CHANGE] remove userservice and userrole (#527) +- refactor: [BREAKING_CHANGE] remove default validate plugin (#526) +- docs: fix doc build (#524) +- docs: fix middleware typo (#519) +- docs(quickstart): fix keys again (#515) +- docs(quickstart): fix keys (#511) +- docs: add cookie and session (#510) +- docs: fix html closing tag in quickstart (#512) +- docs: quickstart tip (#502) +- docs: add English version of `egg and koa` (#490) +- feat: remove default customEgg (#487) +- doc: add the view config for the egg-view-nunjucks (#496) +- test: add qs security test cases (#491) +- docs: remove meaningless word (#488) + +# 1.0.0-rc.2 / 2017-03-01 + +- deps: upgrade egg-session@2 to support external session store (#480) +- docs: fix view plugin config at quickstart (#482) +- docs: update document for view that using egg-view (#475) +- docs: add config merge to faq (#478) +- docs(doc): add english version of "what is egg" (#462) +- docs: fix deployment link (#473) +- docs: add document for deployment (#448) +- test: travis test on node 8 using nightly building (#464) +- docs: seperate cluster-and-ipc and cluster-client (#441) +- docs: fixed typos 'BS' (#461) +- docs: fixed spelling mistake (#460) +- test: disable error log to stderr (#453) +- docs: fix async-function demo link (#457) +- feat: throw if config.keys not exists when access app.keys (#443) +- docs: add year to licence && mysql docs (#447) +- feat: extend runInBackground on application (#442) + +# 1.0.0-rc.1 / 2017-02-23 + +- feat: [BREAKING_CHANGE] reimplement view, use egg-view plugin (#402) +- fix: listen CookieLimitExceed in app (#429) +- fix: close gracefully (#419) +- docs: correct spelling mistake (#424) +- feat: log error when cookie value's length exceed the limit (#418) +- docs: Update mysql.md (#422) +- docs: add more complete example code for quickstart (#412) +- fix: deprecate warning when inspect & toJSON (#408) +- docs: should listen egg-ready using messenger (#406) +- docs: correct english description at README (#400) +- docs: fix character type error and link reference error (#396) +- docs: add csrf to faq (#393) +- fix: keep unhandledRejectionError err object stack (#390) +- docs: use compress replace bodyparser for example (#391) +- docs: add directory structure (#383) +- docs: add api-doc (#369) +- docs: how to use koa's middleware (#386) +- feat: dump config both after loaded and ready (#377) +- docs: fix filename in config.md (#376) +- docs: add plugin dep name description (#374) +- docs: update version automatically (#367) +- doc: add pm2 faq (#370) +- docs: fix jsonp config in controller.md (#372) +- feat: [BREAKING_CHANGE] remove notfound.enableRedirect (#368) +- docs: add resource page (#364) +- docs: add config result description (#365) +- deps: upgrade egg-mock (#362) +- docs: english wip description & remove unuse file (#361) +- docs: add tutorials index & fix async (#359) + +# 0.12.0 / 2017-02-12 + +- docs: fix async link (#357) +- docs: add async await (#349) +- docs: typo Github > GitHub (#356) +- docs: update site style (#340) +- deps: upgrade egg-core (#350) +- docs: add description to config/env file (#348) +- docs: add APIClient concept to cluster doc (#344) +- test: add async test case (#339) +- feat: view base promise to support async function (#343) +- feat: curl return promise (#342) +- test: add class style controller tests (#336) +- docs: add cnzz (#335) +- test: improve coverage to 100% (#333) +- docs: update egg-and-koa with async function (#334) +- fix: remove tair and hsf (#332) +- docs: quickstart - use controller class (#329) + +# 0.11.0 / 2017-02-07 + +- feat: remove overrideMethod middleware (#324) +- feat: remove worker client, use app.cluster (#282) +- chore(scripts): Add PATH to find hexo (#327) +- docs: fix quickstart example code (#326) +- chore(scripts): deploy document by travis (#325) +- docs: add httpclient tracer demo and docs (#313) +- feat: close cluster clients before app close (#310) +- test: mv benchmark to eggjs/benchmark (#320) +- docs: document for plugin.{env}.js and the reason of plugin name (#321) +- docs: add sigleton in plugin.md (#316) +- docs: plugin and framework list use github tags (#318) +- docs: remove outdated docs (#319) +- docs: controller support class and refactor jsonp (#314) +- docs: add more details about csrf (#315) + +# 0.10.0 / 2017-02-03 + +- feat: remove tracer (#311) +- refactor: use app.beforeClose (#306) +- feat: move ctx.runtime to egg-instrument (#302) +- feat: merge the api of application/agent from extend to instance (#294) +- docs: add egg-security config to router docs (#303) +- style: fix code style for app and config (#300) +- refactor: remove ctx.jsonp and add egg-jsonp plugin (#299) +- docs: fix typo $app to app (#297) +- docs: remove inner links (#298) + +# 0.9.0 / 2017-01-22 + +- feat: remove isAjax (#295) +- test: fix cookie test cases (#296) +- docs: adjust some words (#291) +- feat: move clusterPort to egg-cluster (#281) +- feat: move app.Service egg-core (#279) +- docs: change egg-bin to egg-init (#284) +- docs: improve framework doc based on eggjs/examples#9 (#267) +- feat: remove instrument (#283) +- docs: add progressive link && adjust en docs directory (#275) +- docs: add progressive usage (#268) + +# 0.8.0 / 2017-01-18 + +- test: dep -> dependencies (#270) +- docs: translate zh-cn/basics/app-start.md into english (#222) +- docs: fix quickstart typo (#266) +- docs: add http client debug docs (#265) +- docs: modify and fix 3 points (#264) +- docs(intro): improve decription (#263) +- docs: fix docs site version (#262) +- docs: Fix typo. (#261) +- docs: review 1st version docs (#257) +- fix: typo conext -> context (#259) +- docs: contributing && readme && deps (#253) +- docs: fix quickstart link in index.html (#256) +- docs: set the default locale zh-cn (#255) +- refactor: ctx.realStatus delegate ctx.response.realStatus (#252) +- docs: Add intro/index.md (#246) +- feat: adjust default plugins (#251) +- docs: add RESTful documents (#247) +- feat: delegate ctx.jsonp to ctx.response.jsonp (#248) +- chore: remove examples (#245) +- docs: improve mysql doc +- docs: add mysql doc +- docs: view (#228) +- docs: improve doc theme (#230) +- docs: add core/unittest.md (#199) +- docs: add advanced/framework.md (#225) + +# 0.7.0 / 2017-01-12 + +- docs: add service doc (#221) +- docs: serverEnv => env (#239) +- feat: delegate configurations in app (#233) +- refactor: remove ctx.getCookie, ctx.setCookie and ctx.deleteCookie (#240) +- docs: remove mon-printable character (#242) +- feat: support app.config.proxy to identify app is behind a proxy (#231) +- doc: add plugin doc (#224) +- docs: add Quick Start in English (#223) +- docs: add basics/controller.md (#209) +- docs: add core/development.md (#214) +- docs: remove init.js from document, use app.beforeStart (#229) +- docs: quickstart (#217) +- docs: add security plugin doc (#196) +- docs: mv cluster.md to zh-cn (#216) +- feat: add cluster-client (#191) +- docs: add basics/router.md (#203) +- docs: add advanced/loader.md (#198) +- docs: fix i18n doc (#210) +- docs: add core/i18n.md (#208) +- docs: add core/httpclient document (#197) +- docs: typo (#207) +- docs: add core/logger.md (#204) +- docs: add one more reason why not use koa 2 (#206) +- docs: add error handling (#205) +- docs: add schedule (#202) +- docs: add english translation of basics/env.md +- docs: basics/middleware (#194) +- docs: add basics/config.md (#188) +- doc: app start (#193) +- docs: rename koa.md to egg-and-koa.md (#190) +- docs: egg and koa (#179) +- doc: add basics/env.md (#178) +- doc: rename guide/basics/extend.md to basics/extend.md (#189) +- doc: guide/basics/extend doc (#187) + +# 0.6.3 / 2016-12-30 + +- refactor: use logger.close, .end is deprecated (#171) + +# 0.6.2 / 2016-12-22 + +- refactor(config): set keepAliveTimeout 4000ms by default (#165) + +# 0.6.1 / 2016-12-21 + +- refactor: use sendToApp/sendToAgent in worker client +- fix: protocolHeaders can split with whitespace (#164) +- deps: update version (#157) + +# 0.6.0 / 2016-12-03 + +- deps: egg-cookies@2 (#155) +- fix: already supported in egg-core (#154) +- feat: body parser support disable, ignore and match (#150) +- feat: use appInfo.root in config (#147) +- test: refactor workclient test cases (#145) +- feat: add a dns cache httpclient (#146) + +# 0.5.0 / 2016-11-04 + +- deps: upgrade dependencies (#144) +- feat: warn when agent send message before started (#143) +- feat: [BREAKING_CHANGE] refactor Messenger (#141) +- feat: print error to console on unittest env (#139) +- feat: add ip setter on request (#138) +- feat: add getLogger to app and ctx (#136) +- test: remove co-sleep deps +- test: add local server for curl test cases +- test: use fs read instead of curl test on runInBackground + +# 0.4.0 / 2016-10-29 + +- deps: update version (#135) +- feat: support background task on ctx (#119) +- chore: add middleware example (#121) + +# 0.3.0 / 2016-10-28 + +- test: fix unstable test (#133) +- feat: close return promise (#128) +- deps: update deps version (#113) +- fix: AppWorkerClient subscribe same data failed issue (#110) + +# 0.2.1 / 2016-09-16 + +- feat(application): emit startTimeout event (#107) +- perf: get header using lower case (#106) +- chore: remove --fix for error check but not fix (#101) +- doc: Add Installation (#95) +- doc: add title (#94) + +# 0.2.0 / 2016-09-03 + +- docs: improve documents +- test: update benchmark scripts (#79) +- test: add router for bench cases (#78) +- fix: set header use lowercase (#76) +- test: add toa benchmark (#75) +- test: add benchmark results (#74) +- test: fix security tests (#73) +- test: egg-view-nunjucks change views -> view (#72) + +# 0.1.3 / 2016-08-31 + +- fix: utils.assign support undefined (#71) +- refactor: change accept to getter (#68) + +# 0.1.2 / 2016-08-31 + +- deps: egg-security@1 (#67) +- Revert raw header (#65) +- feat: [BREAKING_CHANGE] remove poweredBy && config.core (#63) + +# 0.1.1 / 2016-08-29 + +- refactor: use ctx.setRawHeader (#61) +- chore: add benchmarks (#62) +- fix(meta): remove server-id (#56) +- feat(response): add res.setRawHeader (#60) +- refator: use utils.assign instead of Object.assign (#59) +- feat: docs structure (#55) +- docs: web.md and web.zh_CN.md (#54) + +# 0.1.0 / 2016-08-18 + +- feat: [BREAKING_CHANGE] use egg-core (#44) +- doc: translate to EN (#25) +- fix: Error of no such file or directory, scandir '/restful_api/app/api' (#42) +- test: fix default plugins test (#37) +- feat: add inner plugins (#24) +- docs: add schedule example (#30) + +# 0.0.5 / 2016-07-20 + +- refactor(core): let ctx.cookies become a getter (#22) +- fix(messenger): init when create app and agent (#21) +- test: add test codes (#20) -0.1.0 / 2016-08-18 -================== +# 0.0.1 / 2016-07-13 - * feat: [BREAKING_CHANGE] use egg-core (#44) - * doc: translate to EN (#25) - * fix: Error of no such file or directory, scandir '/restful_api/app/api' (#42) - * test: fix default plugins test (#37) - * feat: add inner plugins (#24) - * docs: add schedule example (#30) - -0.0.5 / 2016-07-20 -================== - - * refactor(core): let ctx.cookies become a getter (#22) - * fix(messenger): init when create app and agent (#21) - * test: add test codes (#20) - -0.0.1 / 2016-07-13 -================== - - * init version +- init version diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60c879bfa4..dc6ae7c440 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,7 +35,7 @@ All features must be submitted along with documentations. The documentations sho - Documentations must clarify one or more aspects of the feature, depending on the nature of feature: what it is, why it happens and how it works. - It's better to include a series of procedues to explain how to fix the problem. You are also encourgaed to provide **simple, but self-explanatory** demo. -All demos should be compiled at [eggjs/examples](https://github.com/eggjs/examples) repository. + All demos should be compiled at [eggjs/examples](https://github.com/eggjs/examples) repository. - Please provide essential urls, such as application process, terminology explainations and references. ## Pulling and Submitting Code @@ -217,9 +217,9 @@ In the release of every stable version, there will be a PM who has the following - Confirm that performance test is passed and all issues in current Milestone are either closed or can be delayed to later versions. - Open a new [Release Proposal MR], and write `History` as [node CHANGELOG]. Don't forget to correct content in documentation which is related to the releasing version. Commits can be generated automatically. - ```bash - $ npm run commits - ``` + ```bash + $ npm run commits + ``` - Nominate PM for next stable version. diff --git a/CONTRIBUTING.zh-CN.md b/CONTRIBUTING.zh-CN.md index 7f13de5d60..be3fa8d518 100644 --- a/CONTRIBUTING.zh-CN.md +++ b/CONTRIBUTING.zh-CN.md @@ -25,7 +25,7 @@ - 此时 issue 会被非常高的优先级进行处理。 - 如果此 bug 是正在影响线上应用正常运行,会再打上 `critical`,代表是最高优先级,需要马上立刻处理! - bug 会在最低需要修复的版本进行修复,如是在 `0.9.x` 要修复的,而当前最新版本是 `1.1.x`, - 那么此 issue 还会被打上 `0.9`,`0.10`,`1.0`,`1.1`,代表需要修复到这些版本。 + 那么此 issue 还会被打上 `0.9`,`0.10`,`1.0`,`1.1`,代表需要修复到这些版本。 - `core: xx`: 代表 issue 跟 core 内核相关,如 `core: antx` 代表跟 `antx` 配置相关。 - `plugin: xx`: 代表 issue 跟插件相关,如 `deps: session` 代表跟 `session` 插件相关。 - `deps: xx`: 代表 issue 跟 `dependencies` 模块相关,如 `deps: egg-cors` 代表跟 `egg-cors` 模块相关。 @@ -38,7 +38,7 @@ - 必须说清楚问题的几个方面:what(是什么),why(为什么),how(怎么做),可根据问题的特性有所侧重。 - how 部分必须包含详尽完整的操作步骤,必要时附上 **足够简单,可运行** 的范例代码, -所有范例代码放在 [eggjs/examples](https://github.com/eggjs/examples) 库中。 + 所有范例代码放在 [eggjs/examples](https://github.com/eggjs/examples) 库中。 - 提供必要的链接,如申请流程,术语解释和参考文档等。 - 同步修改中英文文档,或者在 PR 里面说明。 @@ -163,7 +163,7 @@ BREAKING CHANGE: 英语正文按照一般英语语法规律书写即可,但标题比较特殊,应该按照以下规范进行书写: -- 名词、动词、代词、形容词、副词等首字母大写,介词、冠词、连词、感叹词和助词首字母小写,*标题第一个单词、最后一个单词无论词性首字母应该大写*。 +- 名词、动词、代词、形容词、副词等首字母大写,介词、冠词、连词、感叹词和助词首字母小写,_标题第一个单词、最后一个单词无论词性首字母应该大写_。 - 专有名词(如直接引用某个变量,或者某个插件名称等),必须使用反单引号(键盘上 Esc 正下方)进行引用,并保持原来大小写。 - 超过5个字母的介词首字母应该大写,否则一律小写。 - 如果是重要提示性标题,或者是专有名称标题(例如 Http 请求方法:GET,POST,PUT,DELETE),可以全部字母都用大写(慎重考虑)。 @@ -219,9 +219,9 @@ egg 基于 [semver] 语义化版本号进行发布。 - 确认当前发布里程碑所有的已知问题都已关闭或可延期,完成性能测试。 - 发起一个新的 [发布合并请求],按照 [node 变更日志] 进行 `History` 的编写,修正文档中与版本相关的内容,commits 可以自动生成: - ```bash - $ npm run commits - ``` + ```bash + $ npm run commits + ``` - 指定下一个大版本的 PM。 diff --git a/History.md b/History.md index 861881bbf9..22b30053fd 100644 --- a/History.md +++ b/History.md @@ -1,52 +1,53 @@ - -3.29.0 / 2024-11-30 -================== +# 3.29.0 / 2024-11-30 **features** - * [[`e4f706990`](http://github.com/eggjs/egg/commit/e4f7069904b99c842e65692f2531a72543719207)] - feat: use urllib@4.5.0 (#5371) (fengmk2 <>) -3.28.0 / 2024-09-16 -================== +- [[`e4f706990`](http://github.com/eggjs/egg/commit/e4f7069904b99c842e65692f2531a72543719207)] - feat: use urllib@4.5.0 (#5371) (fengmk2 <>) + +# 3.28.0 / 2024-09-16 **features** - * [[`46d3fb222`](http://github.com/eggjs/egg/commit/46d3fb222bcf455d2aee9a99005d18c271f29b16)] - feat: support allowH2 on urllib@4 (#5357) (fengmk2 <>) -3.27.1 / 2024-07-12 -================== +- [[`46d3fb222`](http://github.com/eggjs/egg/commit/46d3fb222bcf455d2aee9a99005d18c271f29b16)] - feat: support allowH2 on urllib@4 (#5357) (fengmk2 <>) + +# 3.27.1 / 2024-07-12 **fixes** - * [[`f3d8df1b`](http://github.com/eggjs/egg/commit/f3d8df1b7c2aef88cca3beec8c753656f8cc629c)] - fix: add httpclient.safeCurl typing (#5341) (killa <>) -3.27.0 / 2024-07-12 -================== +- [[`f3d8df1b`](http://github.com/eggjs/egg/commit/f3d8df1b7c2aef88cca3beec8c753656f8cc629c)] - fix: add httpclient.safeCurl typing (#5341) (killa <>) + +# 3.27.0 / 2024-07-12 **features** - * [[`68cbd241`](http://github.com/eggjs/egg/commit/68cbd241e2172b8018328d77ea087dd5974a580f)] - feat: impl httpclient.safeCurl (#5339) (killa <>) -3.26.1 / 2024-07-04 -================== +- [[`68cbd241`](http://github.com/eggjs/egg/commit/68cbd241e2172b8018328d77ea087dd5974a580f)] - feat: impl httpclient.safeCurl (#5339) (killa <>) + +# 3.26.1 / 2024-07-04 **fixes** - * [[`872273cb`](http://github.com/eggjs/egg/commit/872273cb23cd6f5d76b3f33528916effade31011)] - fix: xframe value type (#5336) (hongzzz <>) + +- [[`872273cb`](http://github.com/eggjs/egg/commit/872273cb23cd6f5d76b3f33528916effade31011)] - fix: xframe value type (#5336) (hongzzz <>) **others** - * [[`8ae76d09`](http://github.com/eggjs/egg/commit/8ae76d09db8cf020cbdacfc64fee0750b9612136)] - docs: fix typo (#5330) (Fu Yuchen <<78291982+fyc09@users.noreply.github.com>>) -3.26.0 / 2024-07-01 -================== +- [[`8ae76d09`](http://github.com/eggjs/egg/commit/8ae76d09db8cf020cbdacfc64fee0750b9612136)] - docs: fix typo (#5330) (Fu Yuchen <<78291982+fyc09@users.noreply.github.com>>) + +# 3.26.0 / 2024-07-01 **features** - * [[`b0292a8b`](http://github.com/eggjs/egg/commit/b0292a8b7e76d5dbf7441b7164c39441dbae51ec)] - feat: allow to create httpClient from app (#5334) (fengmk2 <>) -3.25.0 / 2024-06-27 -================== +- [[`b0292a8b`](http://github.com/eggjs/egg/commit/b0292a8b7e76d5dbf7441b7164c39441dbae51ec)] - feat: allow to create httpClient from app (#5334) (fengmk2 <>) + +# 3.25.0 / 2024-06-27 **features** - * [[`ceded0b1`](http://github.com/eggjs/egg/commit/ceded0b1c9217503c5ed9226f96c493d6bd00547)] - feat: allow to httpClient use HTTP2 first (#5332) (fengmk2 <>) + +- [[`ceded0b1`](http://github.com/eggjs/egg/commit/ceded0b1c9217503c5ed9226f96c493d6bd00547)] - feat: allow to httpClient use HTTP2 first (#5332) (fengmk2 <>) **others** - * [[`8553c3f2`](http://github.com/eggjs/egg/commit/8553c3f23e423e9f60144b11a484b703fe7c9229)] - chore: remove auto release (fengmk2 <>) - * [[`b4f01a1c`](http://github.com/eggjs/egg/commit/b4f01a1c6bf006c943c85fce334b81d61f55b7d0)] - chore: fix release branches name (fengmk2 <>) - * [[`a8073b04`](http://github.com/eggjs/egg/commit/a8073b04fc3821bb23326c6c8b4fd0ccaeb5c200)] - chore: add release config (fengmk2 <>) - * [[`8ce2ff90`](http://github.com/eggjs/egg/commit/8ce2ff90bfbb9e4580a23ea49a15fdb1c185fbb5)] - chore: add npm publish tag (fengmk2 <>) - * [[`44950ed8`](http://github.com/eggjs/egg/commit/44950ed82a3ce4d5d4b9028aee98d6650298a552)] - chore: start 3.x LTS (fengmk2 <>) + +- [[`8553c3f2`](http://github.com/eggjs/egg/commit/8553c3f23e423e9f60144b11a484b703fe7c9229)] - chore: remove auto release (fengmk2 <>) +- [[`b4f01a1c`](http://github.com/eggjs/egg/commit/b4f01a1c6bf006c943c85fce334b81d61f55b7d0)] - chore: fix release branches name (fengmk2 <>) +- [[`a8073b04`](http://github.com/eggjs/egg/commit/a8073b04fc3821bb23326c6c8b4fd0ccaeb5c200)] - chore: add release config (fengmk2 <>) +- [[`8ce2ff90`](http://github.com/eggjs/egg/commit/8ce2ff90bfbb9e4580a23ea49a15fdb1c185fbb5)] - chore: add npm publish tag (fengmk2 <>) +- [[`44950ed8`](http://github.com/eggjs/egg/commit/44950ed82a3ce4d5d4b9028aee98d6650298a552)] - chore: start 3.x LTS (fengmk2 <>) diff --git a/agent.js b/agent.js index 17fbdc32eb..068dfb0f45 100644 --- a/agent.js +++ b/agent.js @@ -1,6 +1,6 @@ -'use strict'; +"use strict"; -const BaseHookClass = require('./lib/core/base_hook_class'); +const BaseHookClass = require("./lib/core/base_hook_class"); class EggAgentHook extends BaseHookClass { configDidLoad() { diff --git a/app/extend/context.js b/app/extend/context.js index 83bef2499b..1b40167261 100644 --- a/app/extend/context.js +++ b/app/extend/context.js @@ -1,20 +1,19 @@ -'use strict'; +"use strict"; -const { performance } = require('node:perf_hooks'); -const delegate = require('delegates'); -const { assign } = require('utility'); -const eggUtils = require('egg-core').utils; +const { performance } = require("node:perf_hooks"); +const delegate = require("delegates"); +const { assign } = require("utility"); +const eggUtils = require("egg-core").utils; -const HELPER = Symbol('Context#helper'); -const LOCALS = Symbol('Context#locals'); -const LOCALS_LIST = Symbol('Context#localsList'); -const COOKIES = Symbol('Context#cookies'); -const CONTEXT_LOGGERS = Symbol('Context#logger'); -const CONTEXT_HTTPCLIENT = Symbol('Context#httpclient'); -const CONTEXT_ROUTER = Symbol('Context#router'); - -const proto = module.exports = { +const HELPER = Symbol("Context#helper"); +const LOCALS = Symbol("Context#locals"); +const LOCALS_LIST = Symbol("Context#localsList"); +const COOKIES = Symbol("Context#cookies"); +const CONTEXT_LOGGERS = Symbol("Context#logger"); +const CONTEXT_HTTPCLIENT = Symbol("Context#httpclient"); +const CONTEXT_ROUTER = Symbol("Context#router"); +const proto = (module.exports = { /** * Get the current visitor's cookies. */ @@ -127,7 +126,7 @@ const proto = module.exports = { * ``` */ get logger() { - return this.getLogger('logger'); + return this.getLogger("logger"); }, /** @@ -138,7 +137,7 @@ const proto = module.exports = { * @since 1.0.0 */ get coreLogger() { - return this.getLogger('coreLogger'); + return this.getLogger("coreLogger"); }, /** @@ -216,7 +215,7 @@ const proto = module.exports = { /* istanbul ignore next */ const taskName = scope._name || scope.name || eggUtils.getCalleeFromStack(true); scope._name = taskName; - this._runInBackground(scope); + void this._runInBackground(scope); }, // let plugins or frameworks to reuse _runInBackground in some cases. @@ -227,59 +226,67 @@ const proto = module.exports = { /* istanbul ignore next */ const taskName = scope._name || scope.name || eggUtils.getCalleeFromStack(true); // use setImmediate to ensure all sync logic will run async - return new Promise(resolve => setImmediate(resolve)) - // use app.toAsyncFunction to support both generator function and async function - .then(() => ctx.app.toAsyncFunction(scope)(ctx)) - .then(() => { - ctx.coreLogger.info('[egg:background] task:%s success (%dms)', - taskName, Math.floor((performance.now() - start) * 1000) / 1000); - }) - .catch(err => { - // background task process log - ctx.coreLogger.info('[egg:background] task:%s fail (%dms)', - taskName, Math.floor((performance.now() - start) * 1000) / 1000); + return ( + new Promise((resolve) => setImmediate(resolve)) + // use app.toAsyncFunction to support both generator function and async function + .then(() => ctx.app.toAsyncFunction(scope)(ctx)) + .then(() => { + ctx.coreLogger.info( + "[egg:background] task:%s success (%dms)", + taskName, + Math.floor((performance.now() - start) * 1000) / 1000, + ); + }) + .catch((err) => { + // background task process log + ctx.coreLogger.info( + "[egg:background] task:%s fail (%dms)", + taskName, + Math.floor((performance.now() - start) * 1000) / 1000, + ); - // emit error when promise catch, and set err.runInBackground flag - err.runInBackground = true; - ctx.app.emit('error', err, ctx); - }); + // emit error when promise catch, and set err.runInBackground flag + err.runInBackground = true; + ctx.app.emit("error", err, ctx); + }) + ); }, -}; +}); /** * Context delegation. */ -delegate(proto, 'request') +delegate(proto, "request") /** * @member {Boolean} Context#acceptJSON * @see Request#acceptJSON * @since 1.0.0 */ - .getter('acceptJSON') + .getter("acceptJSON") /** * @member {Array} Context#queries * @see Request#queries * @since 1.0.0 */ - .getter('queries') + .getter("queries") /** * @member {Boolean} Context#accept * @see Request#accept * @since 1.0.0 */ - .getter('accept') + .getter("accept") /** * @member {string} Context#ip * @see Request#ip * @since 1.0.0 */ - .access('ip'); + .access("ip"); -delegate(proto, 'response') +delegate(proto, "response") /** * @member {Number} Context#realStatus * @see Response#realStatus * @since 1.0.0 */ - .access('realStatus'); + .access("realStatus"); diff --git a/app/extend/helper.js b/app/extend/helper.js index 5b86eaef89..7f25d2ce97 100644 --- a/app/extend/helper.js +++ b/app/extend/helper.js @@ -1,10 +1,8 @@ -'use strict'; - -const url = require('node:url'); +"use strict"; +const url = require("node:url"); module.exports = { - /** * Generate URL path(without host) for route. Takes the route name and a map of named params. * @function Helper#pathFor @@ -37,7 +35,11 @@ module.exports = { * @return {String} full url(with host) */ urlFor(name, params) { - return this.ctx.protocol + '://' + this.ctx.host + url.resolve('/', this.app.router.url(name, params)); + return ( + this.ctx.protocol + + "://" + + this.ctx.host + + url.resolve("/", this.app.router.url(name, params)) + ); }, - }; diff --git a/app/extend/request.js b/app/extend/request.js index c496351beb..5239d658d6 100644 --- a/app/extend/request.js +++ b/app/extend/request.js @@ -1,15 +1,15 @@ -'use strict'; +"use strict"; -const querystring = require('node:querystring'); -const accepts = require('accepts'); +const querystring = require("node:querystring"); +const accepts = require("accepts"); -const _querycache = Symbol('_querycache'); -const _queriesCache = Symbol('_queriesCache'); -const PROTOCOL = Symbol('PROTOCOL'); -const HOST = Symbol('HOST'); -const ACCEPTS = Symbol('ACCEPTS'); -const IPS = Symbol('IPS'); -const RE_ARRAY_KEY = /[^\[\]]+\[\]$/; +const _querycache = Symbol("_querycache"); +const _queriesCache = Symbol("_queriesCache"); +const PROTOCOL = Symbol("PROTOCOL"); +const HOST = Symbol("HOST"); +const ACCEPTS = Symbol("ACCEPTS"); +const IPS = Symbol("IPS"); +const RE_ARRAY_KEY = /[^[\]]+\[\]$/; module.exports = { /** @@ -36,7 +36,7 @@ module.exports = { if (this.app.config.proxy) { host = getFromHeaders(this, this.app.config.hostHeaders); } - host = host || this.get('host') || ''; + host = host || this.get("host") || ""; this[HOST] = host.split(/\s*,\s*/)[0]; return this[HOST]; }, @@ -53,7 +53,7 @@ module.exports = { if (this[PROTOCOL]) return this[PROTOCOL]; // detect encrypted socket if (this.socket && this.socket.encrypted) { - this[PROTOCOL] = 'https'; + this[PROTOCOL] = "https"; return this[PROTOCOL]; } // get from headers specified in `app.config.protocolHeaders` @@ -65,7 +65,7 @@ module.exports = { } } // use protocol specified in `app.conig.protocol` - this[PROTOCOL] = this.app.config.protocol || 'http'; + this[PROTOCOL] = this.app.config.protocol || "http"; return this[PROTOCOL]; }, @@ -89,12 +89,14 @@ module.exports = { return this[IPS]; } - const val = getFromHeaders(this, this.app.config.ipHeaders) || ''; + const val = getFromHeaders(this, this.app.config.ipHeaders) || ""; this[IPS] = val ? val.split(/\s*,\s*/) : []; let maxIpsCount = this.app.config.maxIpsCount; // Compatible with maxProxyCount logic (previous logic is wrong, only for compatibility with legacy logic) - if (!maxIpsCount && this.app.config.maxProxyCount) maxIpsCount = this.app.config.maxProxyCount + 1; + if (!maxIpsCount && this.app.config.maxProxyCount) { + maxIpsCount = this.app.config.maxProxyCount + 1; + } if (maxIpsCount > 0) { // if maxIpsCount present, only keep `maxIpsCount` ips @@ -122,7 +124,7 @@ module.exports = { const ip = this.ips[0] || this.socket.remoteAddress; // will be '::ffff:x.x.x.x', should convert to standard IPv4 format // https://zh.wikipedia.org/wiki/IPv6 - this._ip = ip && ip.indexOf('::ffff:') > -1 ? ip.substring(7) : ip; + this._ip = ip && ip.indexOf("::ffff:") > -1 ? ip.substring(7) : ip; return this._ip; }, @@ -151,16 +153,16 @@ module.exports = { * @since 1.0.0 */ get acceptJSON() { - if (this.path.endsWith('.json')) return true; - if (this.response.type && this.response.type.indexOf('json') >= 0) return true; - if (this.accepts('html', 'text', 'json') === 'json') return true; + if (this.path.endsWith(".json")) return true; + if (this.response.type && this.response.type.indexOf("json") >= 0) return true; + if (this.accepts("html", "text", "json") === "json") return true; return false; }, // How to read query safely // https://github.com/koajs/qs/issues/5 _customQuery(cacheName, filter) { - const str = this.querystring || ''; + const str = this.querystring || ""; let c = this[cacheName]; if (!c) { c = this[cacheName] = {}; @@ -256,7 +258,6 @@ module.exports = { }, }; - function firstValue(value) { if (Array.isArray(value)) { value = value[0]; @@ -266,17 +267,17 @@ function firstValue(value) { function arrayValue(value) { if (!Array.isArray(value)) { - value = [ value ]; + value = [value]; } return value; } function getFromHeaders(ctx, names) { - if (!names) return ''; + if (!names) return ""; names = names.split(/\s*,\s*/); for (const name of names) { const value = ctx.get(name); if (value) return value; } - return ''; + return ""; } diff --git a/app/extend/response.js b/app/extend/response.js index 643d53f610..dc4f9704dd 100644 --- a/app/extend/response.js +++ b/app/extend/response.js @@ -1,12 +1,11 @@ -'use strict'; +"use strict"; -const getType = require('cache-content-type'); -const isJSON = require('koa-is-json'); +const getType = require("cache-content-type"); +const isJSON = require("koa-is-json"); -const REAL_STATUS = Symbol('Context#realStatus'); +const REAL_STATUS = Symbol("Context#realStatus"); module.exports = { - /** * Get or set the length of content. * @@ -19,17 +18,17 @@ module.exports = { set length(len) { // copy from koa // change header name to lower case - this.set('content-length', len); + this.set("content-length", len); }, get length() { // copy from koa - const len = this.header['content-length']; + const len = this.header["content-length"]; const body = this.body; if (len == null) { if (!body) return; - if (typeof body === 'string') return Buffer.byteLength(body); + if (typeof body === "string") return Buffer.byteLength(body); if (Buffer.isBuffer(body)) return body.length; if (isJSON(body)) return Buffer.byteLength(JSON.stringify(body)); return; @@ -55,17 +54,17 @@ module.exports = { // - change header name to lower case type = getType(type); if (type) { - this.set('content-type', type); + this.set("content-type", type); } else { - this.remove('content-type'); + this.remove("content-type"); } }, get type() { // copy from koa - const type = this.get('content-type'); - if (!type) return ''; - return type.split(';')[0]; + const type = this.get("content-type"); + if (!type) return ""; + return type.split(";")[0]; }, /** diff --git a/app/middleware/body_parser.js b/app/middleware/body_parser.js index 70f473a33d..1d3cde2782 100644 --- a/app/middleware/body_parser.js +++ b/app/middleware/body_parser.js @@ -1,3 +1,3 @@ -'use strict'; +"use strict"; -module.exports = require('koa-bodyparser'); +module.exports = require("koa-bodyparser"); diff --git a/app/middleware/meta.js b/app/middleware/meta.js index 5ef169092d..bbc5ccdc3e 100644 --- a/app/middleware/meta.js +++ b/app/middleware/meta.js @@ -2,19 +2,26 @@ * meta middleware, should be the first middleware */ -const { performance } = require('node:perf_hooks'); +const { performance } = require("node:perf_hooks"); -module.exports = options => { +module.exports = (options) => { return async function meta(ctx, next) { if (options.logging) { - ctx.coreLogger.info('[meta] request started, host: %s, user-agent: %s', ctx.host, ctx.header['user-agent']); + ctx.coreLogger.info( + "[meta] request started, host: %s, user-agent: %s", + ctx.host, + ctx.header["user-agent"], + ); } await next(); // total response time header if (ctx.performanceStarttime) { - ctx.set('x-readtime', Math.floor((performance.now() - ctx.performanceStarttime) * 1000) / 1000); + ctx.set( + "x-readtime", + Math.floor((performance.now() - ctx.performanceStarttime) * 1000) / 1000, + ); } else { - ctx.set('x-readtime', Date.now() - ctx.starttime); + ctx.set("x-readtime", Date.now() - ctx.starttime); } }; }; diff --git a/app/middleware/notfound.js b/app/middleware/notfound.js index 4ec4288f8e..bf7506fdc8 100644 --- a/app/middleware/notfound.js +++ b/app/middleware/notfound.js @@ -1,6 +1,6 @@ -'use strict'; +"use strict"; -module.exports = options => { +module.exports = (options) => { return async function notfound(ctx, next) { await next(); @@ -13,12 +13,12 @@ module.exports = options => { if (ctx.acceptJSON) { ctx.body = { - message: 'Not Found', + message: "Not Found", }; return; } - const notFoundHtml = '

404 Not Found

'; + const notFoundHtml = "

404 Not Found

"; // notfound handler is unimplemented if (options.pageUrl && ctx.path === options.pageUrl) { diff --git a/app/middleware/override_method.js b/app/middleware/override_method.js index bf5f7ef0f4..daa0504a7d 100644 --- a/app/middleware/override_method.js +++ b/app/middleware/override_method.js @@ -1,3 +1,3 @@ -'use strict'; +"use strict"; -module.exports = require('koa-override'); +module.exports = require("koa-override"); diff --git a/app/middleware/site_file.js b/app/middleware/site_file.js index cb403d9a97..9d93afe00b 100644 --- a/app/middleware/site_file.js +++ b/app/middleware/site_file.js @@ -1,26 +1,26 @@ -'use strict'; +"use strict"; -const path = require('node:path'); +const path = require("node:path"); -module.exports = options => { +module.exports = (options) => { return async function siteFile(ctx, next) { - if (ctx.method !== 'HEAD' && ctx.method !== 'GET') return next(); + if (ctx.method !== "HEAD" && ctx.method !== "GET") return next(); /* istanbul ignore if */ - if (ctx.path[0] !== '/') return next(); + if (ctx.path[0] !== "/") return next(); let content = options[ctx.path]; if (!content) return next(); // '/favicon.ico': 'https://eggjs.org/favicon.ico' or '/favicon.ico': async (ctx) => 'https://eggjs.org/favicon.ico' // content is function - if (typeof content === 'function') content = await content(ctx); + if (typeof content === "function") content = await content(ctx); // content is url - if (typeof content === 'string') return ctx.redirect(content); + if (typeof content === "string") return ctx.redirect(content); // '/robots.txt': Buffer { - +module.exports = (appInfo) => { const config = { - /** * The environment of egg * @member {String} Config#env @@ -36,7 +35,7 @@ module.exports = appInfo => { * @default * @since 1.0.0 */ - keys: '', + keys: "", /** * default cookie options @@ -86,7 +85,7 @@ module.exports = appInfo => { * @default * @since 1.0.0 */ - protocolHeaders: 'x-forwarded-proto', + protocolHeaders: "x-forwarded-proto", /** * Detect request' ip from specified headers, not case-sensitive. @@ -95,7 +94,7 @@ module.exports = appInfo => { * @default * @since 1.0.0 */ - ipHeaders: 'x-forwarded-for', + ipHeaders: "x-forwarded-for", /** * Detect request' host from specified headers, not case-sensitive. @@ -104,7 +103,7 @@ module.exports = appInfo => { * @default * @since 1.0.0 */ - hostHeaders: '', + hostHeaders: "", /** * package.json @@ -136,7 +135,7 @@ module.exports = appInfo => { * @default * @since 1.0.0 */ - rundir: path.join(appInfo.baseDir, 'run'), + rundir: path.join(appInfo.baseDir, "run"), /** * dump config @@ -148,7 +147,14 @@ module.exports = appInfo => { */ dump: { ignore: new Set([ - 'pass', 'pwd', 'passd', 'passwd', 'password', 'keys', 'masterKey', 'accessKey', + "pass", + "pwd", + "passd", + "passwd", + "password", + "keys", + "masterKey", + "accessKey", // ignore any key contains "secret" keyword /secret/i, ]), @@ -167,11 +173,11 @@ module.exports = appInfo => { * @type {Object} */ confusedConfigurations: { - bodyparser: 'bodyParser', - notFound: 'notfound', - sitefile: 'siteFile', - middlewares: 'middleware', - httpClient: 'httpclient', + bodyparser: "bodyParser", + notFound: "notfound", + sitefile: "siteFile", + middlewares: "middleware", + httpClient: "httpclient", }, }; @@ -185,7 +191,7 @@ module.exports = appInfo => { * @property {String} pageUrl - the 404 page url */ config.notfound = { - pageUrl: '', + pageUrl: "", }; /** @@ -202,9 +208,9 @@ module.exports = appInfo => { * }; */ config.siteFile = { - '/favicon.ico': fs.readFileSync(path.join(__dirname, 'favicon.png')), + "/favicon.ico": fs.readFileSync(path.join(__dirname, "favicon.png")), // default cache in 30 days - cacheControl: 'public, max-age=2592000', + cacheControl: "public, max-age=2592000", }; /** @@ -225,10 +231,10 @@ module.exports = appInfo => { */ config.bodyParser = { enable: true, - encoding: 'utf8', - formLimit: '1mb', - jsonLimit: '1mb', - textLimit: '1mb', + encoding: "utf8", + formLimit: "1mb", + jsonLimit: "1mb", + textLimit: "1mb", strict: true, // @see https://github.com/hapijs/qs/blob/master/lib/parse.js#L8 for more options queryString: { @@ -237,7 +243,7 @@ module.exports = appInfo => { parameterLimit: 1000, }, onerror(err, ctx) { - err.message += ', check bodyParser config'; + err.message += ", check bodyParser config"; if (ctx.status === 404) { // set default status to 400, meaning client bad request ctx.status = 400; @@ -268,18 +274,18 @@ module.exports = appInfo => { * @property {Boolean} enableFastContextLogger - using the app logger instead of EggContextLogger, defaults to false */ config.logger = { - dir: path.join(appInfo.root, 'logs', appInfo.name), - encoding: 'utf8', + dir: path.join(appInfo.root, "logs", appInfo.name), + encoding: "utf8", env: appInfo.env, - level: 'INFO', - consoleLevel: 'INFO', - disableConsoleAfterReady: appInfo.env !== 'local' && appInfo.env !== 'unittest', + level: "INFO", + consoleLevel: "INFO", + disableConsoleAfterReady: appInfo.env !== "local" && appInfo.env !== "unittest", outputJSON: false, buffer: true, appLogName: `${appInfo.name}-web.log`, - coreLogName: 'egg-web.log', - agentLogName: 'egg-agent.log', - errorLogName: 'common-error.log', + coreLogName: "egg-web.log", + agentLogName: "egg-agent.log", + errorLogName: "common-error.log", coreLogger: {}, allowDebugAtProd: false, enablePerformanceTimer: false, @@ -346,13 +352,7 @@ module.exports = appInfo => { * core enable middlewares * @member {Array} Config#middleware */ - config.coreMiddleware = [ - 'meta', - 'siteFile', - 'notfound', - 'bodyParser', - 'overrideMethod', - ]; + config.coreMiddleware = ["meta", "siteFile", "notfound", "bodyParser", "overrideMethod"]; /** * emit `startTimeout` if worker don't ready after `workerStartTimeout` ms @@ -380,9 +380,9 @@ module.exports = appInfo => { */ config.cluster = { listen: { - path: '', + path: "", port: 7001, - hostname: '', + hostname: "", }, }; @@ -403,9 +403,9 @@ module.exports = appInfo => { * The response to be returned should include properties below: * * @member {Function} Config#onClientError - * @property [body] {String|Buffer} - the response body - * @property [status] {Number} - the response status code - * @property [headers] {Object} - the response header key-value pairs + * @property {String|Buffer} [body] - the response body + * @property {Number} [status] - the response status code + * @property {Object} [headers] - the response header key-value pairs * * @example * exports.onClientError = async (err, socket, app) => { diff --git a/config/config.local.js b/config/config.local.js index 2924388133..b1e7a16121 100644 --- a/config/config.local.js +++ b/config/config.local.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; exports.logger = { coreLogger: { - consoleLevel: 'WARN', + consoleLevel: "WARN", }, }; diff --git a/config/config.unittest.js b/config/config.unittest.js index 7c5c5e4c6d..e576f0d814 100644 --- a/config/config.unittest.js +++ b/config/config.unittest.js @@ -1,8 +1,8 @@ -'use strict'; +"use strict"; module.exports = { logger: { - consoleLevel: 'WARN', + consoleLevel: "WARN", buffer: false, }, }; diff --git a/config/plugin.js b/config/plugin.js index da864347eb..bc9125a503 100644 --- a/config/plugin.js +++ b/config/plugin.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; module.exports = { // enable plugins @@ -10,7 +10,7 @@ module.exports = { */ onerror: { enable: true, - package: 'egg-onerror', + package: "egg-onerror", }, /** @@ -21,7 +21,7 @@ module.exports = { */ session: { enable: true, - package: 'egg-session', + package: "egg-session", }, /** @@ -32,7 +32,7 @@ module.exports = { */ i18n: { enable: true, - package: 'egg-i18n', + package: "egg-i18n", }, /** @@ -43,7 +43,7 @@ module.exports = { */ watcher: { enable: true, - package: 'egg-watcher', + package: "egg-watcher", }, /** @@ -54,7 +54,7 @@ module.exports = { */ multipart: { enable: true, - package: 'egg-multipart', + package: "egg-multipart", }, /** @@ -65,7 +65,7 @@ module.exports = { */ security: { enable: true, - package: 'egg-security', + package: "egg-security", }, /** @@ -76,7 +76,7 @@ module.exports = { */ development: { enable: true, - package: 'egg-development', + package: "egg-development", }, /** @@ -87,7 +87,7 @@ module.exports = { */ logrotator: { enable: true, - package: 'egg-logrotator', + package: "egg-logrotator", }, /** @@ -98,7 +98,7 @@ module.exports = { */ schedule: { enable: true, - package: 'egg-schedule', + package: "egg-schedule", }, /** @@ -109,7 +109,7 @@ module.exports = { */ static: { enable: true, - package: 'egg-static', + package: "egg-static", }, /** @@ -120,7 +120,7 @@ module.exports = { */ jsonp: { enable: true, - package: 'egg-jsonp', + package: "egg-jsonp", }, /** @@ -131,6 +131,6 @@ module.exports = { */ view: { enable: true, - package: 'egg-view', + package: "egg-view", }, }; diff --git a/eslint.config.mjs b/eslint.config.mjs deleted file mode 100644 index 2ef684b895..0000000000 --- a/eslint.config.mjs +++ /dev/null @@ -1,25 +0,0 @@ -import { fixupConfigRules } from '@eslint/compat'; -import { FlatCompat } from '@eslint/eslintrc'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const compat = new FlatCompat({ - baseDirectory: __dirname, -}); - -export default [ - { - ignores: [ - 'test/fixtures/**', - 'examples/**/app/public/**', - 'logs/**', - 'run/**', - 'docs/node_modules/**', - 'site/**', - ], - }, - ...fixupConfigRules(compat.extends('eslint-config-egg')), -]; diff --git a/index.d.ts b/index.d.ts index 28ed159299..85c36fbd0b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,11 +1,11 @@ -import accepts = require('accepts'); -import { AsyncLocalStorage } from 'async_hooks'; -import { EventEmitter } from 'events' -import { Readable } from 'stream'; -import { Socket, LookupFunction } from 'net'; -import { IncomingMessage, ServerResponse } from 'http'; -import KoaApplication = require('koa'); -import KoaRouter = require('koa-router'); +import accepts = require("accepts"); +import { AsyncLocalStorage } from "node:async_hooks"; +import { EventEmitter } from "node:events"; +import { Readable } from "node:stream"; +import { Socket, LookupFunction } from "node:net"; +import { IncomingMessage, ServerResponse } from "node:http"; +import KoaApplication = require("koa"); +import KoaRouter = require("koa-router"); import { EggLogger as Logger, EggLoggers, @@ -13,20 +13,17 @@ import { EggLoggersOptions, EggLoggerOptions, EggContextLogger, -} from 'egg-logger'; +} from "egg-logger"; import { RequestOptions2 as RequestOptionsOld, HttpClientResponse as HttpClientResponseOld, -} from 'urllib'; +} from "urllib"; import { RequestURL, RequestOptions, HttpClientResponse as HttpClientResponseNext, -} from 'urllib-next'; -import { - FetchFactory, - fetch, -} from 'urllib4'; +} from "urllib-next"; +import { FetchFactory, fetch } from "urllib4"; import { EggCoreBase, FileLoaderOption, @@ -34,22 +31,22 @@ import { EggCoreOptions as CoreOptions, EggLoaderOptions as CoreLoaderOptions, BaseContextClass as CoreBaseContextClass, -} from 'egg-core'; -import EggCookies = require('egg-cookies'); -import 'egg-onerror'; -import 'egg-session'; -import 'egg-i18n'; -import 'egg-watcher'; -import 'egg-multipart'; -import 'egg-security'; -import 'egg-development'; -import 'egg-logrotator'; -import 'egg-schedule'; -import 'egg-static'; -import 'egg-jsonp'; -import 'egg-view'; - -declare module 'egg' { +} from "egg-core"; +import EggCookies = require("egg-cookies"); +import "egg-onerror"; +import "egg-session"; +import "egg-i18n"; +import "egg-watcher"; +import "egg-multipart"; +import "egg-security"; +import "egg-development"; +import "egg-logrotator"; +import "egg-schedule"; +import "egg-static"; +import "egg-jsonp"; +import "egg-view"; + +declare module "egg" { export type EggLogger = Logger; // plain object type PlainObject = { [key: string]: T }; @@ -69,24 +66,36 @@ declare module 'egg' { export type HttpClientResponse = HttpClientResponseNext; // Compatible with both urllib@2 and urllib@3 RequestOptions to request export interface EggHttpClient extends EventEmitter { - request(url: HttpClientRequestURL): Promise | HttpClientResponse>; - request(url: HttpClientRequestURL, options: RequestOptionsOld | HttpClientRequestOptions): - Promise | HttpClientResponse>; - curl(url: HttpClientRequestURL): Promise | HttpClientResponse>; - curl(url: HttpClientRequestURL, options: RequestOptionsOld | HttpClientRequestOptions): - Promise | HttpClientResponse>; - safeCurl(url: HttpClientRequestURL): Promise | HttpClientResponse>; - safeCurl(url: HttpClientRequestURL, options: RequestOptionsOld | HttpClientRequestOptions): - Promise | HttpClientResponse>; + request( + url: HttpClientRequestURL, + ): Promise | HttpClientResponse>; + request( + url: HttpClientRequestURL, + options: RequestOptionsOld | HttpClientRequestOptions, + ): Promise | HttpClientResponse>; + curl( + url: HttpClientRequestURL, + ): Promise | HttpClientResponse>; + curl( + url: HttpClientRequestURL, + options: RequestOptionsOld | HttpClientRequestOptions, + ): Promise | HttpClientResponse>; + safeCurl( + url: HttpClientRequestURL, + ): Promise | HttpClientResponse>; + safeCurl( + url: HttpClientRequestURL, + options: RequestOptionsOld | HttpClientRequestOptions, + ): Promise | HttpClientResponse>; } interface EggHttpConstructor { - new(app: Application): EggHttpClient; + new (app: Application): EggHttpClient; } - export interface EggContextHttpClient extends EggHttpClient { } + export interface EggContextHttpClient extends EggHttpClient {} interface EggContextHttpClientConstructor { - new(ctx: Context): EggContextHttpClient; + new (ctx: Context): EggContextHttpClient; } /** @@ -94,7 +103,13 @@ declare module 'egg' { * it's instantiated in context level, * {@link Helper}, {@link Service} is extending it. */ - export class BaseContextClass extends CoreBaseContextClass { // tslint:disable-line + export class BaseContextClass extends CoreBaseContextClass< + Context, + Application, + EggAppConfig, + IService + > { + // tslint:disable-line /** * logger */ @@ -129,7 +144,8 @@ declare module 'egg' { export type RequestArrayBody = any[]; export type RequestObjectBody = PlainObject; - export interface Request extends KoaApplication.Request { // tslint:disable-line + export interface Request extends KoaApplication.Request { + // tslint:disable-line /** * detect if response should be json * 1. url path ends with `.json` @@ -211,7 +227,8 @@ declare module 'egg' { body: any; } - export interface Response extends KoaApplication.Response { // tslint:disable-line + export interface Response extends KoaApplication.Response { + // tslint:disable-line /** * read response real status code. * @@ -227,7 +244,6 @@ declare module 'egg' { export type LoggerLevel = EggLoggerLevel; - /** * egg app info * @example @@ -255,7 +271,7 @@ declare module 'egg' { type IgnoreOrMatch = IgnoreItem | IgnoreItem[]; /** logger config of egg */ - export interface EggLoggerConfig extends RemoveSpecProp { + export interface EggLoggerConfig extends RemoveSpecProp { /** custom config of coreLogger */ coreLogger?: Partial; /** allow debug log at prod, defaults to `false` */ @@ -269,11 +285,14 @@ declare module 'egg' { } /** Custom Loader Configuration */ - export interface CustomLoaderConfig extends RemoveSpecProp { + export interface CustomLoaderConfig extends RemoveSpecProp< + FileLoaderOption, + "inject" | "target" + > { /** * an object you wanner load to, value can only be 'ctx' or 'app'. default to app */ - inject?: 'ctx' | 'app'; + inject?: "ctx" | "app"; /** * whether need to load files in plugins or framework, default to false */ @@ -295,9 +314,7 @@ declare module 'egg' { maxFreeSockets?: number; } - type Dispatcher = FetchFactory['getDispatcher'] extends () => infer R - ? R - : never; + type Dispatcher = FetchFactory["getDispatcher"] extends () => infer R ? R : never; /** HttpClient config */ export interface HttpClientConfig extends HttpClientBaseConfig { @@ -323,7 +340,7 @@ declare module 'egg' { allowH2?: boolean; /** Custom lookup function for DNS resolution */ lookup?: LookupFunction; - interceptors?: Parameters; + interceptors?: Parameters; } export interface EggAppConfig { workerStartTimeout: number; @@ -370,7 +387,7 @@ declare module 'egg' { text: string[]; }; /** Default is `'error'`, it will return `400` response when `Prototype-Poisoning` happen. */ - onProtoPoisoning: 'error' | 'remove' | 'ignore'; + onProtoPoisoning: "error" | "remove" | "ignore"; }; /** @@ -533,11 +550,11 @@ declare module 'egg' { }; xframe: { enable: boolean; - value: 'SAMEORIGIN' | 'DENY' | string; + value: "SAMEORIGIN" | "DENY" | string; }; hsts: any; methodnoallow: { enable: boolean }; - noopen: { enable: boolean; } + noopen: { enable: boolean }; xssProtection: any; csp: any; }; @@ -546,7 +563,11 @@ declare module 'egg' { watcher: PlainObject; - onClientError(err: Error, socket: Socket, app: EggApplication): ClientErrorResponse | Promise; + onClientError( + err: Error, + socket: Socket, + app: EggApplication, + ): ClientErrorResponse | Promise; /** * server timeout in milliseconds, default to 0 (no timeout). @@ -566,7 +587,7 @@ declare module 'egg' { headers: { [key: string]: string }; } - export interface Router extends Omit, 'url'> { + export interface Router extends Omit, "url"> { /** * restful router api */ @@ -593,7 +614,10 @@ declare module 'egg' { methods: string[]; } - export interface EggApplication extends Omit, 'ctxStorage' | 'currentContext'> { + export interface EggApplication extends Omit< + EggCoreBase, + "ctxStorage" | "currentContext" + > { /** * HttpClient instance */ @@ -603,7 +627,7 @@ declare module 'egg' { * node fetch */ FetchFactory: FetchFactory; - fetch: typeof fetch, + fetch: typeof fetch; /** * Logger for Application, wrapping app.coreLogger with context infomation @@ -650,7 +674,7 @@ declare module 'egg' { * Keep the same api with httpclient.request(url, args). * See https://github.com/node-modules/urllib#api-doc for more details. */ - curl: EggHttpClient['request']; + curl: EggHttpClient["request"]; /** * Get logger by name, it's equal to app.loggers['name'], but you can extend it with your own logical @@ -761,20 +785,21 @@ declare module 'egg' { /** * Get current execute ctx async local storage - * @returns {AsyncLocalStorage} localStorage - store current execute Context + * @return {AsyncLocalStorage} localStorage - store current execute Context */ get ctxStorage(): AsyncLocalStorage; /** * Get current execute ctx, maybe undefined - * @returns {Context} ctx - current execute Context + * @return {Context} ctx - current execute Context */ get currentContext(): Context; } - export interface IApplicationLocals extends PlainObject { } + export interface IApplicationLocals extends PlainObject {} - export interface FileStream extends Readable { // tslint:disable-line + export interface FileStream extends Readable { + // tslint:disable-line fields: any; filename: string; @@ -809,23 +834,23 @@ declare module 'egg' { file: any, filename: string, encoding: string, - mimetype: string + mimetype: string, ): void | Error; } /** - * KoaApplication's Context will carry the default 'cookie' property in - * the egg's Context interface, which is wrong here because we have our own - * special properties (e.g: encrypted). So we must remove this property and - * create our own with the same name. - * @see https://github.com/eggjs/egg/pull/2958 - * - * However, the latest version of Koa has "[key: string]: any" on the - * context, and there'll be a type error for "keyof koa.Context". - * So we have to directly inherit from "KoaApplication.BaseContext" and - * rewrite all the properties to be compatible with types in Koa. - * @see https://github.com/eggjs/egg/pull/3329 - */ + * KoaApplication's Context will carry the default 'cookie' property in + * the egg's Context interface, which is wrong here because we have our own + * special properties (e.g: encrypted). So we must remove this property and + * create our own with the same name. + * @see https://github.com/eggjs/egg/pull/2958 + * + * However, the latest version of Koa has "[key: string]: any" on the + * context, and there'll be a type error for "keyof koa.Context". + * So we have to directly inherit from "KoaApplication.BaseContext" and + * rewrite all the properties to be compatible with types in Koa. + * @see https://github.com/eggjs/egg/pull/3329 + */ export interface Context extends KoaApplication.BaseContext { [key: string]: any; body: ResponseBodyT; @@ -1026,7 +1051,7 @@ declare module 'egg' { * Keep the same api with httpclient.request(url, args). * See https://github.com/node-modules/urllib#api-doc for more details. */ - curl: EggHttpClient['request']; + curl: EggHttpClient["request"]; __(key: string, ...values: string[]): string; gettext(key: string, ...values: string[]): string; @@ -1054,13 +1079,13 @@ declare module 'egg' { httpclient: EggContextHttpClient; } - export interface IContextLocals extends PlainObject { } + export interface IContextLocals extends PlainObject {} - export class Controller extends BaseContextClass { } + export class Controller extends BaseContextClass {} - export class Service extends BaseContextClass { } + export class Service extends BaseContextClass {} - export class Subscription extends BaseContextClass { } + export class Subscription extends BaseContextClass {} /** * The empty interface `IService` is a placeholder, for egg @@ -1081,11 +1106,11 @@ declare module 'egg' { * * Now I can get ctx.service.foo at controller and other service file. */ - export interface IService extends PlainObject { } // tslint:disable-line + export interface IService extends PlainObject {} // tslint:disable-line - export interface IController extends PlainObject { } // tslint:disable-line + export interface IController extends PlainObject {} // tslint:disable-line - export interface IMiddleware extends PlainObject { } // tslint:disable-line + export interface IMiddleware extends PlainObject {} // tslint:disable-line export interface IHelper extends PlainObject, BaseContextClass { /** @@ -1121,7 +1146,7 @@ declare module 'egg' { } // egg env type - export type EggEnvType = 'local' | 'unittest' | 'prod' | string; + export type EggEnvType = "local" | "unittest" | "prod" | string; /** * plugin config item interface @@ -1157,8 +1182,7 @@ declare module 'egg' { /** * Singleton instance in Agent Worker, extend {@link EggApplication} */ - export class Agent extends EggApplication { - } + export class Agent extends EggApplication {} export interface ClusterOptions { /** specify framework that can be absolute path or npm package */ @@ -1191,7 +1215,7 @@ declare module 'egg' { ignoreWarning?: boolean; } - export function start(options?: StartOptions): Promise + export function start(options?: StartOptions): Promise; /** * Powerful Partial, Support adding ? modifier to a mapped property in deep level @@ -1202,9 +1226,7 @@ declare module 'egg' { * type EggConfig = PowerPartial */ export type PowerPartial = { - [U in keyof T]?: T[U] extends object - ? PowerPartial - : T[U] + [U in keyof T]?: T[U] extends object ? PowerPartial : T[U]; }; // send data can be number|string|boolean|object but not Set|Map @@ -1239,8 +1261,8 @@ declare module 'egg' { } // compatible - export interface EggLoaderOptions extends CoreLoaderOptions { } - export interface EggLoader extends CoreLoader { } + export interface EggLoaderOptions extends CoreLoaderOptions {} + export interface EggLoader extends CoreLoader {} /** * App worker process Loader, will load plugins @@ -1303,4 +1325,4 @@ declare module 'egg' { export interface Singleton { get(id: string): T; } -} \ No newline at end of file +} diff --git a/index.js b/index.js index 7e3269eda3..c9e92192da 100644 --- a/index.js +++ b/index.js @@ -6,63 +6,63 @@ * Start egg application with cluster mode * @since 1.0.0 */ -exports.startCluster = require('egg-cluster').startCluster; +exports.startCluster = require("egg-cluster").startCluster; /** * Start egg application with single process mode * @since 1.0.0 */ -exports.start = require('./lib/start'); +exports.start = require("./lib/start"); /** * @member {Application} Egg#Application * @since 1.0.0 */ -exports.Application = require('./lib/application'); +exports.Application = require("./lib/application"); /** * @member {Agent} Egg#Agent * @since 1.0.0 */ -exports.Agent = require('./lib/agent'); +exports.Agent = require("./lib/agent"); /** * @member {AppWorkerLoader} Egg#AppWorkerLoader * @since 1.0.0 */ -exports.AppWorkerLoader = require('./lib/loader').AppWorkerLoader; +exports.AppWorkerLoader = require("./lib/loader").AppWorkerLoader; /** * @member {AgentWorkerLoader} Egg#AgentWorkerLoader * @since 1.0.0 */ -exports.AgentWorkerLoader = require('./lib/loader').AgentWorkerLoader; +exports.AgentWorkerLoader = require("./lib/loader").AgentWorkerLoader; /** * @member {Controller} Egg#Controller * @since 1.1.0 */ -exports.Controller = require('./lib/core/base_context_class'); +exports.Controller = require("./lib/core/base_context_class"); /** * @member {Service} Egg#Service * @since 1.1.0 */ -exports.Service = require('./lib/core/base_context_class'); +exports.Service = require("./lib/core/base_context_class"); /** * @member {Subscription} Egg#Subscription * @since 1.10.0 */ -exports.Subscription = require('./lib/core/base_context_class'); +exports.Subscription = require("./lib/core/base_context_class"); /** * @member {BaseContextClass} Egg#BaseContextClass * @since 1.2.0 */ -exports.BaseContextClass = require('./lib/core/base_context_class'); +exports.BaseContextClass = require("./lib/core/base_context_class"); /** * @member {Boot} Egg#Boot */ -exports.Boot = require('./lib/core/base_hook_class'); +exports.Boot = require("./lib/core/base_hook_class"); diff --git a/index.test-d.ts b/index.test-d.ts index 8f7bcd336e..d90889f394 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1 +1 @@ -import '.'; +import "."; diff --git a/lib/agent.js b/lib/agent.js index 0e3013db8d..1163537279 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -1,12 +1,12 @@ -'use strict'; +"use strict"; -const path = require('node:path'); -const ms = require('ms'); -const EggApplication = require('./egg'); -const AgentWorkerLoader = require('./loader').AgentWorkerLoader; +const path = require("node:path"); +const ms = require("ms"); +const EggApplication = require("./egg"); +const AgentWorkerLoader = require("./loader").AgentWorkerLoader; -const EGG_LOADER = Symbol.for('egg#loader'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const EGG_LOADER = Symbol.for("egg#loader"); +const EGG_PATH = Symbol.for("egg#eggPath"); /** * Singleton instance in Agent Worker, extend {@link EggApplication} @@ -18,7 +18,7 @@ class Agent extends EggApplication { * @param {Object} options - see {@link EggApplication} */ constructor(options = {}) { - options.type = 'agent'; + options.type = "agent"; super(options); this.loader.load(); @@ -26,16 +26,13 @@ class Agent extends EggApplication { // dump config after loaded, ensure all the dynamic modifications will be recorded const dumpStartTime = Date.now(); this.dumpConfig(); - this.coreLogger.info( - '[egg:core] dump config after load, %s', - ms(Date.now() - dumpStartTime) - ); + this.coreLogger.info("[egg:core] dump config after load, %s", ms(Date.now() - dumpStartTime)); // keep agent alive even it doesn't have any io tasks this.agentAliveHandler = setInterval(() => {}, 24 * 60 * 60 * 1000); this._uncaughtExceptionHandler = this._uncaughtExceptionHandler.bind(this); - process.on('uncaughtException', this._uncaughtExceptionHandler); + process.on("uncaughtException", this._uncaughtExceptionHandler); } _uncaughtExceptionHandler(err) { @@ -43,8 +40,8 @@ class Agent extends EggApplication { err = new Error(String(err)); } /* istanbul ignore else */ - if (err.name === 'Error') { - err.name = 'unhandledExceptionError'; + if (err.name === "Error") { + err.name = "unhandledExceptionError"; } this.coreLogger.error(err); } @@ -54,39 +51,29 @@ class Agent extends EggApplication { } get [EGG_PATH]() { - return path.join(__dirname, '..'); + return path.join(__dirname, ".."); } _wrapMessenger() { - for (const methodName of [ - 'broadcast', - 'sendTo', - 'sendToApp', - 'sendToAgent', - 'sendRandom', - ]) { + for (const methodName of ["broadcast", "sendTo", "sendToApp", "sendToAgent", "sendRandom"]) { wrapMethod(methodName, this.messenger, this.coreLogger); } function wrapMethod(methodName, messenger, logger) { const originMethod = messenger[methodName]; - messenger[methodName] = function() { - const stack = new Error().stack.split('\n').slice(1).join('\n'); - logger.warn( - "agent can't call %s before server started\n%s", - methodName, - stack - ); + messenger[methodName] = function () { + const stack = new Error().stack.split("\n").slice(1).join("\n"); + logger.warn("agent can't call %s before server started\n%s", methodName, stack); originMethod.apply(this, arguments); }; - messenger.prependOnceListener('egg-ready', () => { + messenger.prependOnceListener("egg-ready", () => { messenger[methodName] = originMethod; }); } } close() { - process.removeListener('uncaughtException', this._uncaughtExceptionHandler); + process.removeListener("uncaughtException", this._uncaughtExceptionHandler); clearInterval(this.agentAliveHandler); return super.close(); } diff --git a/lib/application.js b/lib/application.js index c13dfa8854..31290fecf3 100644 --- a/lib/application.js +++ b/lib/application.js @@ -1,27 +1,27 @@ -'use strict'; - -const path = require('node:path'); -const fs = require('node:fs'); -const ms = require('ms'); -const is = require('is-type-of'); -const graceful = require('graceful'); -const http = require('node:http'); -const cluster = require('cluster-client'); -const onFinished = require('on-finished'); -const { assign } = require('utility'); -const eggUtils = require('egg-core').utils; -const EggApplication = require('./egg'); -const AppWorkerLoader = require('./loader').AppWorkerLoader; - -const KEYS = Symbol('Application#keys'); -const HELPER = Symbol('Application#Helper'); -const LOCALS = Symbol('Application#locals'); -const BIND_EVENTS = Symbol('Application#bindEvents'); -const WARN_CONFUSED_CONFIG = Symbol('Application#warnConfusedConfig'); -const EGG_LOADER = Symbol.for('egg#loader'); -const EGG_PATH = Symbol.for('egg#eggPath'); -const CLUSTER_CLIENTS = Symbol.for('egg#clusterClients'); -const RESPONSE_RAW = Symbol('Application#responseRaw'); +"use strict"; + +const path = require("node:path"); +const fs = require("node:fs"); +const ms = require("ms"); +const is = require("is-type-of"); +const graceful = require("graceful"); +const http = require("node:http"); +const cluster = require("cluster-client"); +const onFinished = require("on-finished"); +const { assign } = require("utility"); +const eggUtils = require("egg-core").utils; +const EggApplication = require("./egg"); +const AppWorkerLoader = require("./loader").AppWorkerLoader; + +const KEYS = Symbol("Application#keys"); +const HELPER = Symbol("Application#Helper"); +const LOCALS = Symbol("Application#locals"); +const BIND_EVENTS = Symbol("Application#bindEvents"); +const WARN_CONFUSED_CONFIG = Symbol("Application#warnConfusedConfig"); +const EGG_LOADER = Symbol.for("egg#loader"); +const EGG_PATH = Symbol.for("egg#eggPath"); +const CLUSTER_CLIENTS = Symbol.for("egg#clusterClients"); +const RESPONSE_RAW = Symbol("Application#responseRaw"); // client error => 400 Bad Request // Refs: https://nodejs.org/dist/latest-v8.x/docs/api/http.html#http_event_clienterror @@ -41,7 +41,7 @@ const DEFAULT_BAD_REQUEST_RESPONSE = function escapeHeaderValue(value) { // Protect against response splitting. The regex test is there to // minimize the performance impact in the common case. - return /[\r\n]/.test(value) ? value.replace(/[\r\n]+[ \t]*/g, '') : value; + return /[\r\n]/.test(value) ? value.replace(/[\r\n]+[ \t]*/g, "") : value; } // Refs: https://github.com/nodejs/node/blob/b38c81/lib/_http_outgoing.js#L706-L710 @@ -50,13 +50,12 @@ function escapeHeaderValue(value) { * @augments EggApplication */ class Application extends EggApplication { - /** * @class * @param {Object} options - see {@link EggApplication} */ constructor(options = {}) { - options.type = 'application'; + options.type = "application"; super(options); // will auto set after 'server' event emit @@ -73,7 +72,7 @@ class Application extends EggApplication { // dump config after loaded, ensure all the dynamic modifications will be recorded const dumpStartTime = Date.now(); this.dumpConfig(); - this.coreLogger.info('[egg:core] dump config after load, %s', ms(Date.now() - dumpStartTime)); + this.coreLogger.info("[egg:core] dump config after load, %s", ms(Date.now() - dumpStartTime)); this[WARN_CONFUSED_CONFIG](); this[BIND_EVENTS](); @@ -84,7 +83,7 @@ class Application extends EggApplication { } get [EGG_PATH]() { - return path.join(__dirname, '..'); + return path.join(__dirname, ".."); } [RESPONSE_RAW](socket, raw) { @@ -92,17 +91,17 @@ class Application extends EggApplication { if (!socket.writable) return; if (!raw) return socket.end(DEFAULT_BAD_REQUEST_RESPONSE); - const body = (raw.body == null) ? DEFAULT_BAD_REQUEST_HTML : raw.body; + const body = raw.body == null ? DEFAULT_BAD_REQUEST_HTML : raw.body; const headers = raw.headers || {}; const status = raw.status || 400; - let responseHeaderLines = ''; - const firstLine = `HTTP/1.1 ${status} ${http.STATUS_CODES[status] || 'Unknown'}`; + let responseHeaderLines = ""; + const firstLine = `HTTP/1.1 ${status} ${http.STATUS_CODES[status] || "Unknown"}`; // Not that safe because no validation for header keys. // Refs: https://github.com/nodejs/node/blob/b38c81/lib/_http_outgoing.js#L451 for (const key of Object.keys(headers)) { - if (key.toLowerCase() === 'content-length') { + if (key.toLowerCase() === "content-length") { delete headers[key]; continue; } @@ -117,15 +116,17 @@ class Application extends EggApplication { onClientError(err, socket) { // ignore when there is no http body, it almost like an ECONNRESET if (err.rawPacket) { - this.logger.warn('A client (%s:%d) error [%s] occurred: %s', + this.logger.warn( + "A client (%s:%d) error [%s] occurred: %s", socket.remoteAddress, socket.remotePort, err.code, - err.message); + err.message, + ); } - if (typeof this.config.onClientError === 'function') { - const p = eggUtils.callFn(this.config.onClientError, [ err, socket, this ]); + if (typeof this.config.onClientError === "function") { + const p = eggUtils.callFn(this.config.onClientError, [err, socket, this]); // the returned object should be something like: // @@ -142,9 +143,9 @@ class Application extends EggApplication { // + body: '' // + headers: {} // + status: 400 - p.then(ret => { + p.then((ret) => { this[RESPONSE_RAW](socket, ret || {}); - }).catch(err => { + }).catch((err) => { this.logger.error(err); this[RESPONSE_RAW](socket); }); @@ -163,15 +164,22 @@ class Application extends EggApplication { /* istanbul ignore next */ graceful({ - server: [ server ], + server: [server], error: (err, throwErrorCount) => { const originMessage = err.message; if (originMessage) { // shouldjs will override error property but only getter // https://github.com/shouldjs/should.js/blob/889e22ebf19a06bc2747d24cf34b25cc00b37464/lib/assertion-error.js#L26 - Object.defineProperty(err, 'message', { + Object.defineProperty(err, "message", { get() { - return originMessage + ' (uncaughtException throw ' + throwErrorCount + ' times on pid:' + process.pid + ')'; + return ( + originMessage + + " (uncaughtException throw " + + throwErrorCount + + " times on pid:" + + process.pid + + ")" + ); }, configurable: true, enumerable: false, @@ -182,7 +190,7 @@ class Application extends EggApplication { ignoreCode: serverGracefulIgnoreCode, }); - server.on('clientError', (err, socket) => this.onClientError(err, socket)); + server.on("clientError", (err, socket) => this.onClientError(err, socket)); // server timeout if (is.number(this.config.serverTimeout)) server.setTimeout(this.config.serverTimeout); @@ -209,8 +217,8 @@ class Application extends EggApplication { } handleRequest(ctx, fnMiddleware) { - this.emit('request', ctx); - onFinished(ctx.res, () => this.emit('response', ctx)); + this.emit("request", ctx); + onFinished(ctx.res, () => this.emit("response", ctx)); return super.handleRequest(ctx, fnMiddleware); } @@ -225,7 +233,7 @@ class Application extends EggApplication { const rundir = this.config.rundir; const FULLPATH = this.loader.FileLoader.FULLPATH; try { - const dumpRouterFile = path.join(rundir, 'router.json'); + const dumpRouterFile = path.join(rundir, "router.json"); const routers = []; for (const layer of this.router.stack) { routers.push({ @@ -234,7 +242,9 @@ class Application extends EggApplication { paramNames: layer.paramNames, path: layer.path, regexp: layer.regexp.toString(), - stack: layer.stack.map(stack => stack[FULLPATH] || stack._name || stack.name || 'anonymous'), + stack: layer.stack.map( + (stack) => stack[FULLPATH] || stack._name || stack.name || "anonymous", + ), }); } fs.writeFileSync(dumpRouterFile, JSON.stringify(routers, null, 2)); @@ -277,15 +287,15 @@ class Application extends EggApplication { get keys() { if (!this[KEYS]) { if (!this.config.keys) { - if (this.config.env === 'local' || this.config.env === 'unittest') { - const configPath = path.join(this.config.baseDir, 'config/config.default.js'); - console.error('Cookie need secret key to sign and encrypt.'); - console.error('Please add `config.keys` in %s', configPath); + if (this.config.env === "local" || this.config.env === "unittest") { + const configPath = path.join(this.config.baseDir, "config/config.default.js"); + console.error("Cookie need secret key to sign and encrypt."); + console.error("Please add `config.keys` in %s", configPath); } - throw new Error('Please set config.keys first'); + throw new Error("Please set config.keys first"); } - this[KEYS] = this.config.keys.split(',').map(s => s.trim()); + this[KEYS] = this.config.keys.split(",").map((s) => s.trim()); } return this[KEYS]; } @@ -318,15 +328,15 @@ class Application extends EggApplication { */ [BIND_EVENTS]() { // Browser Cookie Limits: http://browsercookielimits.squawky.net/ - this.on('cookieLimitExceed', ({ name, value, ctx }) => { + this.on("cookieLimitExceed", ({ name, value, ctx }) => { const err = new Error(`cookie ${name}'s length(${value.length}) exceed the limit(4093)`); - err.name = 'CookieLimitExceedError'; + err.name = "CookieLimitExceedError"; err.key = name; err.cookie = value; ctx.coreLogger.error(err); }); // expose server to support websocket - this.once('server', server => this.onServer(server)); + this.once("server", (server) => this.onServer(server)); } /** @@ -336,10 +346,13 @@ class Application extends EggApplication { */ [WARN_CONFUSED_CONFIG]() { const confusedConfigurations = this.config.confusedConfigurations; - Object.keys(confusedConfigurations).forEach(key => { + Object.keys(confusedConfigurations).forEach((key) => { if (this.config[key] !== undefined) { - this.logger.warn('Unexpected config key `%s` exists, Please use `%s` instead.', - key, confusedConfigurations[key]); + this.logger.warn( + "Unexpected config key `%s` exists, Please use `%s` instead.", + key, + confusedConfigurations[key], + ); } }); } diff --git a/lib/core/base_context_class.js b/lib/core/base_context_class.js index 1016d60440..86a7ea72ac 100644 --- a/lib/core/base_context_class.js +++ b/lib/core/base_context_class.js @@ -1,9 +1,9 @@ -'use strict'; +"use strict"; -const EggCoreBaseContextClass = require('egg-core').BaseContextClass; -const BaseContextLogger = require('./base_context_logger'); +const EggCoreBaseContextClass = require("egg-core").BaseContextClass; +const BaseContextLogger = require("./base_context_logger"); -const LOGGER = Symbol('BaseContextClass#logger'); +const LOGGER = Symbol("BaseContextClass#logger"); /** * BaseContextClass is a base class that can be extended, diff --git a/lib/core/base_context_logger.js b/lib/core/base_context_logger.js index 6c1dc2c8df..5909059b32 100644 --- a/lib/core/base_context_logger.js +++ b/lib/core/base_context_logger.js @@ -1,4 +1,4 @@ -const CALL = Symbol('BaseContextLogger#call'); +const CALL = Symbol("BaseContextLogger#call"); class BaseContextLogger { /** @@ -18,7 +18,7 @@ class BaseContextLogger { [CALL](method, args) { // add `[${pathName}]` in log - if (this.pathName && typeof args[0] === 'string') { + if (this.pathName && typeof args[0] === "string") { args[0] = `[${this.pathName}] ${args[0]}`; } this.ctx.app.logger[method](...args); @@ -30,7 +30,7 @@ class BaseContextLogger { * @since 1.2.0 */ debug(...args) { - this[CALL]('debug', args); + this[CALL]("debug", args); } /** @@ -39,7 +39,7 @@ class BaseContextLogger { * @since 1.2.0 */ info(...args) { - this[CALL]('info', args); + this[CALL]("info", args); } /** @@ -48,7 +48,7 @@ class BaseContextLogger { * @since 1.2.0 */ warn(...args) { - this[CALL]('warn', args); + this[CALL]("warn", args); } /** @@ -57,7 +57,7 @@ class BaseContextLogger { * @since 1.2.0 */ error(...args) { - this[CALL]('error', args); + this[CALL]("error", args); } } diff --git a/lib/core/base_hook_class.js b/lib/core/base_hook_class.js index b0e65ce77d..d4a3b49bcc 100644 --- a/lib/core/base_hook_class.js +++ b/lib/core/base_hook_class.js @@ -1,10 +1,9 @@ -'use strict'; +"use strict"; -const assert = require('node:assert'); -const INSTANCE = Symbol('BaseHookClass#instance'); +const assert = require("node:assert"); +const INSTANCE = Symbol("BaseHookClass#instance"); class BaseHookClass { - constructor(instance) { this[INSTANCE] = instance; } @@ -18,12 +17,12 @@ class BaseHookClass { } get app() { - assert(this[INSTANCE].type === 'application', 'agent boot should not use app instance'); + assert(this[INSTANCE].type === "application", "agent boot should not use app instance"); return this[INSTANCE]; } get agent() { - assert(this[INSTANCE].type === 'agent', 'app boot should not use agent instance'); + assert(this[INSTANCE].type === "agent", "app boot should not use agent instance"); return this[INSTANCE]; } } diff --git a/lib/core/context_httpclient.js b/lib/core/context_httpclient.js index a1db7d26a5..440e558589 100644 --- a/lib/core/context_httpclient.js +++ b/lib/core/context_httpclient.js @@ -18,8 +18,8 @@ class ContextHttpClient { return await this.app.curl(url, options); } - async request(url, options) { - return await this.curl(url, options); + request(url, options) { + return this.curl(url, options); } } diff --git a/lib/core/dnscache_httpclient.js b/lib/core/dnscache_httpclient.js index ba5e4bcb45..17731b36f1 100644 --- a/lib/core/dnscache_httpclient.js +++ b/lib/core/dnscache_httpclient.js @@ -1,12 +1,12 @@ -const dns = require('node:dns').promises; -const LRU = require('ylru'); -const { assign } = require('utility'); -const HttpClient = require('./httpclient'); -const utils = require('./utils'); +const dns = require("node:dns").promises; +const LRU = require("ylru"); +const { assign } = require("utility"); +const HttpClient = require("./httpclient"); +const utils = require("./utils"); const IP_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; -const DNSLOOKUP = Symbol('DNSCacheHttpClient#dnslookup'); -const UPDATE_DNS = Symbol('DNSCacheHttpClient#updateDNS'); +const DNSLOOKUP = Symbol("DNSCacheHttpClient#dnslookup"); +const UPDATE_DNS = Symbol("DNSCacheHttpClient#updateDNS"); class DNSCacheHttpClient extends HttpClient { constructor(app) { @@ -26,7 +26,7 @@ class DNSCacheHttpClient extends HttpClient { async [DNSLOOKUP](url, args) { let parsed; - if (typeof url === 'string') { + if (typeof url === "string") { parsed = utils.safeParseURL(url); // invalid url or relative url if (!parsed) return { url, args }; @@ -55,7 +55,7 @@ class DNSCacheHttpClient extends HttpClient { if (now - record.timestamp >= this.dnsCacheLookupInterval) { // make sure the next request doesn't refresh dns query record.timestamp = now; - this[UPDATE_DNS](hostname, args).catch(err => this.app.emit('error', err)); + this[UPDATE_DNS](hostname, args).catch((err) => this.app.emit("error", err)); } return { url: formatDnsLookupUrl(hostname, url, record.ip), args }; @@ -69,8 +69,7 @@ class DNSCacheHttpClient extends HttpClient { const logger = args.ctx ? args.ctx.coreLogger : this.app.coreLogger; try { const { address } = await dns.lookup(hostname, { family: 4 }); - logger.info('[dnscache_httpclient] dns lookup success: %s => %s', - hostname, address); + logger.info("[dnscache_httpclient] dns lookup success: %s => %s", hostname, address); this.dnsCache.set(hostname, { timestamp: Date.now(), ip: address }); return address; } catch (err) { @@ -83,7 +82,7 @@ class DNSCacheHttpClient extends HttpClient { module.exports = DNSCacheHttpClient; function formatDnsLookupUrl(host, url, address) { - if (typeof url === 'string') return url.replace(host, address); + if (typeof url === "string") return url.replace(host, address); const urlObj = assign({}, url); urlObj.hostname = urlObj.hostname.replace(host, address); if (urlObj.host) { diff --git a/lib/core/fetch_factory.js b/lib/core/fetch_factory.js index 0b67e9e5c7..d5d23501af 100644 --- a/lib/core/fetch_factory.js +++ b/lib/core/fetch_factory.js @@ -1,6 +1,6 @@ -const debug = require('node:util').debuglog('egg:lib:core:fetch_factory'); +const debug = require("node:util").debuglog("egg:lib:core:fetch_factory"); -const mainNodejsVersion = parseInt(process.versions.node.split('.')[0]); +const mainNodejsVersion = parseInt(process.versions.node.split(".")[0]); let FetchFactory; let fetch; // Track initialization per app instance by storing a WeakMap @@ -11,11 +11,11 @@ let ssrfFetchFactory; if (mainNodejsVersion >= 20) { // urllib@4 only works on Node.js >= 20 try { - const urllib4 = require('urllib4'); + const urllib4 = require("urllib4"); FetchFactory = urllib4.FetchFactory; - debug('urllib4 enable'); + debug("urllib4 enable"); - fetch = function(url, init) { + fetch = function (url, init) { if (!fetchInitializedMap.get(this)) { const clientOptions = {}; if (this.config.httpclient?.lookup) { @@ -44,7 +44,7 @@ if (mainNodejsVersion >= 20) { if (ssrfConfig?.checkAddress) { clientOptions.checkAddress = ssrfConfig.checkAddress; } else { - this.logger.warn('[egg-security] please configure `config.security.ssrf` first'); + this.logger.warn("[egg-security] please configure `config.security.ssrf` first"); } if (this.config.httpclient?.lookup) { clientOptions.lookup = this.config.httpclient.lookup; @@ -61,7 +61,7 @@ if (mainNodejsVersion >= 20) { return ssrfFetchFactory.fetch(url, init); }; } catch (err) { - debug('require urllib4 error: %s', err); + debug("require urllib4 error: %s", err); } } diff --git a/lib/core/httpclient.js b/lib/core/httpclient.js index f3828e800b..537ab70f24 100644 --- a/lib/core/httpclient.js +++ b/lib/core/httpclient.js @@ -1,12 +1,12 @@ -const Agent = require('agentkeepalive'); -const HttpsAgent = require('agentkeepalive').HttpsAgent; -const urllib = require('urllib'); -const ms = require('humanize-ms'); -const { FrameworkBaseError } = require('egg-errors'); +const Agent = require("agentkeepalive"); +const HttpsAgent = require("agentkeepalive").HttpsAgent; +const urllib = require("urllib"); +const ms = require("humanize-ms"); +const { FrameworkBaseError } = require("egg-errors"); class HttpClientError extends FrameworkBaseError { get module() { - return 'httpclient'; + return "httpclient"; } } @@ -35,7 +35,7 @@ class HttpClient extends urllib.HttpClient2 { try { return await super.request(url, args); } catch (err) { - if (err.code === 'ENETUNREACH') { + if (err.code === "ENETUNREACH") { throw HttpClientError.create(err.message, err.code); } throw err; @@ -51,7 +51,7 @@ class HttpClient extends urllib.HttpClient2 { if (ssrfConfig?.checkAddress) { options.checkAddress = ssrfConfig.checkAddress; } else { - this.app.logger.warn('[egg-security] please configure `config.security.ssrf` first'); + this.app.logger.warn("[egg-security] please configure `config.security.ssrf` first"); } return await this.curl(url, options); @@ -62,7 +62,7 @@ function normalizeConfig(app) { const config = app.config.httpclient; // compatibility - if (typeof config.keepAlive === 'boolean') { + if (typeof config.keepAlive === "boolean") { config.httpAgent.keepAlive = config.keepAlive; config.httpsAgent.keepAlive = config.keepAlive; } @@ -92,27 +92,31 @@ function normalizeConfig(app) { } } - if (typeof config.maxSockets === 'number') { + if (typeof config.maxSockets === "number") { config.httpAgent.maxSockets = config.maxSockets; config.httpsAgent.maxSockets = config.maxSockets; } - if (typeof config.maxFreeSockets === 'number') { + if (typeof config.maxFreeSockets === "number") { config.httpAgent.maxFreeSockets = config.maxFreeSockets; config.httpsAgent.maxFreeSockets = config.maxFreeSockets; } if (config.httpAgent.timeout < 30000) { - app.coreLogger.warn('[egg:httpclient] config.httpclient.httpAgent.timeout(%s) can\'t below 30000, auto reset to 30000', - config.httpAgent.timeout); + app.coreLogger.warn( + "[egg:httpclient] config.httpclient.httpAgent.timeout(%s) can't below 30000, auto reset to 30000", + config.httpAgent.timeout, + ); config.httpAgent.timeout = 30000; } if (config.httpsAgent.timeout < 30000) { - app.coreLogger.warn('[egg:httpclient] config.httpclient.httpsAgent.timeout(%s) can\'t below 30000, auto reset to 30000', - config.httpsAgent.timeout); + app.coreLogger.warn( + "[egg:httpclient] config.httpclient.httpsAgent.timeout(%s) can't below 30000, auto reset to 30000", + config.httpsAgent.timeout, + ); config.httpsAgent.timeout = 30000; } - if (typeof config.request.timeout === 'string') { + if (typeof config.request.timeout === "string") { config.request.timeout = ms(config.request.timeout); } } diff --git a/lib/core/httpclient_next.js b/lib/core/httpclient_next.js index 7c80b78277..66531d7a50 100644 --- a/lib/core/httpclient_next.js +++ b/lib/core/httpclient_next.js @@ -1,23 +1,23 @@ -const debug = require('node:util').debuglog('egg:lib:core:httpclient_next'); -const ms = require('humanize-ms'); +const debug = require("node:util").debuglog("egg:lib:core:httpclient_next"); +const ms = require("humanize-ms"); -const SSRF_HTTPCLIENT = Symbol('SSRF_HTTPCLIENT'); +const SSRF_HTTPCLIENT = Symbol("SSRF_HTTPCLIENT"); -const mainNodejsVersion = parseInt(process.versions.node.split('.')[0]); +const mainNodejsVersion = parseInt(process.versions.node.split(".")[0]); let HttpClient; if (mainNodejsVersion >= 20) { // urllib@4 only works on Node.js >= 20 try { - HttpClient = require('urllib4').HttpClient; - debug('urllib4 enable'); + HttpClient = require("urllib4").HttpClient; + debug("urllib4 enable"); } catch (err) { - debug('require urllib4 error: %s', err); + debug("require urllib4 error: %s", err); } } if (!HttpClient) { // fallback to urllib@3 - HttpClient = require('urllib-next').HttpClient; - debug('urllib3 enable'); + HttpClient = require("urllib-next").HttpClient; + debug("urllib3 enable"); } class HttpClientNext extends HttpClient { @@ -61,7 +61,7 @@ class HttpClientNext extends HttpClient { if (ssrfConfig?.checkAddress) { options.checkAddress = ssrfConfig.checkAddress; } else { - this.app.logger.warn('[egg-security] please configure `config.security.ssrf` first'); + this.app.logger.warn("[egg-security] please configure `config.security.ssrf` first"); } if (!options.lookup && this.app.config.httpclient.lookup) { options.lookup = this.app.config.httpclient.lookup; @@ -77,7 +77,7 @@ class HttpClientNext extends HttpClient { function normalizeConfig(app) { const config = app.config.httpclient; - if (typeof config.request.timeout === 'string') { + if (typeof config.request.timeout === "string") { config.request.timeout = ms(config.request.timeout); } } diff --git a/lib/core/logger.js b/lib/core/logger.js index a38dbddcf5..c085449bdf 100644 --- a/lib/core/logger.js +++ b/lib/core/logger.js @@ -1,13 +1,17 @@ -const { EggLoggers } = require('egg-logger'); -const { setCustomLogger } = require('onelogger'); +const { EggLoggers } = require("egg-logger"); +const { setCustomLogger } = require("onelogger"); module.exports = function createLoggers(app) { const loggerConfig = app.config.logger; loggerConfig.type = app.type; loggerConfig.localStorage = app.ctxStorage; - if (app.config.env === 'prod' && loggerConfig.level === 'DEBUG' && !loggerConfig.allowDebugAtProd) { - loggerConfig.level = 'INFO'; + if ( + app.config.env === "prod" && + loggerConfig.level === "DEBUG" && + !loggerConfig.allowDebugAtProd + ) { + loggerConfig.level = "INFO"; } const loggers = new EggLoggers(app.config); @@ -29,7 +33,7 @@ module.exports = function createLoggers(app) { setCustomLogger(loggerName, undefined); } }); - loggers.coreLogger.info('[egg:logger] init all loggers with options: %j', loggerConfig); + loggers.coreLogger.info("[egg:logger] init all loggers with options: %j", loggerConfig); return loggers; }; diff --git a/lib/core/messenger/index.js b/lib/core/messenger/index.js index f819cfa917..1e3ed383ee 100644 --- a/lib/core/messenger/index.js +++ b/lib/core/messenger/index.js @@ -1,14 +1,16 @@ -'use strict'; +"use strict"; -const LocalMessenger = require('./local'); -const IPCMessenger = require('./ipc'); +const LocalMessenger = require("./local"); +const IPCMessenger = require("./ipc"); /** * @class Messenger */ -exports.create = egg => { - return egg.options.mode === 'single' - ? new LocalMessenger(egg) - : new IPCMessenger(egg); +/** + * @param {Object} egg - egg application instance + * @return {Messenger} messenger instance + */ +exports.create = (egg) => { + return egg.options.mode === "single" ? new LocalMessenger(egg) : new IPCMessenger(egg); }; diff --git a/lib/core/messenger/ipc.js b/lib/core/messenger/ipc.js index 155c8fe9df..7ea5835b94 100644 --- a/lib/core/messenger/ipc.js +++ b/lib/core/messenger/ipc.js @@ -1,16 +1,15 @@ -'use strict'; +"use strict"; -const debug = require('node:util').debuglog('egg:util:messenger:ipc'); -const is = require('is-type-of'); -const workerThreads = require('node:worker_threads'); -const sendmessage = require('sendmessage'); -const EventEmitter = require('node:events'); +const debug = require("node:util").debuglog("egg:util:messenger:ipc"); +const is = require("is-type-of"); +const workerThreads = require("node:worker_threads"); +const sendmessage = require("sendmessage"); +const EventEmitter = require("node:events"); /** * Communication between app worker and agent worker by IPC channel */ class Messenger extends EventEmitter { - constructor() { super(); this.pid = String(process.pid); @@ -18,13 +17,13 @@ class Messenger extends EventEmitter { // - retrieve app worker pids when it's an agent worker // - retrieve agent worker pids when it's an app worker this.opids = []; - this.on('egg-pids', pids => { + this.on("egg-pids", (pids) => { this.opids = pids; }); this._onMessage = this._onMessage.bind(this); - process.on('message', this._onMessage); + process.on("message", this._onMessage); if (!workerThreads.isMainThread) { - workerThreads.parentPort.on('message', this._onMessage); + workerThreads.parentPort.on("message", this._onMessage); } } @@ -35,9 +34,9 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ broadcast(action, data) { - debug('[%s] broadcast %s with %j', this.pid, action, data); - this.send(action, data, 'app'); - this.send(action, data, 'agent'); + debug("[%s] broadcast %s with %j", this.pid, action, data); + this.send(action, data, "app"); + this.send(action, data, "agent"); return this; } @@ -49,7 +48,7 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendTo(pid, action, data) { - debug('[%s] send %s with %j to %s', this.pid, action, data, pid); + debug("[%s] send %s with %j to %s", this.pid, action, data, pid); sendmessage(process, { action, data, @@ -81,8 +80,8 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendToApp(action, data) { - debug('[%s] send %s with %j to all app', this.pid, action, data); - this.send(action, data, 'app'); + debug("[%s] send %s with %j to all app", this.pid, action, data); + this.send(action, data, "app"); return this; } @@ -93,8 +92,8 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendToAgent(action, data) { - debug('[%s] send %s with %j to all agent', this.pid, action, data); - this.send(action, data, 'agent'); + debug("[%s] send %s with %j to all agent", this.pid, action, data); + this.send(action, data, "agent"); return this; } @@ -115,14 +114,19 @@ class Messenger extends EventEmitter { _onMessage(message) { if (message && is.string(message.action)) { - debug('[%s] got message %s with %j, receiverPid: %s', - this.pid, message.action, message.data, message.receiverPid); + debug( + "[%s] got message %s with %j, receiverPid: %s", + this.pid, + message.action, + message.data, + message.receiverPid, + ); this.emit(message.action, message.data); } } close() { - process.removeListener('message', this._onMessage); + process.removeListener("message", this._onMessage); this.removeAllListeners(); } diff --git a/lib/core/messenger/local.js b/lib/core/messenger/local.js index 65a9688424..e1bee56e2c 100644 --- a/lib/core/messenger/local.js +++ b/lib/core/messenger/local.js @@ -1,14 +1,13 @@ -'use strict'; +"use strict"; -const debug = require('node:util').debuglog('egg:util:messenger:local'); -const is = require('is-type-of'); -const EventEmitter = require('node:events'); +const debug = require("node:util").debuglog("egg:util:messenger:local"); +const is = require("is-type-of"); +const EventEmitter = require("node:events"); /** * Communication between app worker and agent worker with EventEmitter */ class Messenger extends EventEmitter { - constructor(egg) { super(); this.egg = egg; @@ -21,8 +20,8 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ broadcast(action, data) { - debug('[%s] broadcast %s with %j', this.pid, action, data); - this.send(action, data, 'both'); + debug("[%s] broadcast %s with %j", this.pid, action, data); + this.send(action, data, "both"); return this; } @@ -36,9 +35,9 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendTo(pid, action, data) { - debug('[%s] send %s with %j to %s', this.pid, action, data, pid); + debug("[%s] send %s with %j to %s", this.pid, action, data, pid); if (pid !== process.pid) return this; - this.send(action, data, 'both'); + this.send(action, data, "both"); return this; } @@ -52,8 +51,8 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendRandom(action, data) { - debug('[%s] send %s with %j to opposite', this.pid, action, data); - this.send(action, data, 'opposite'); + debug("[%s] send %s with %j to opposite", this.pid, action, data); + this.send(action, data, "opposite"); return this; } @@ -64,8 +63,8 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendToApp(action, data) { - debug('[%s] send %s with %j to all app', this.pid, action, data); - this.send(action, data, 'application'); + debug("[%s] send %s with %j to all app", this.pid, action, data); + this.send(action, data, "application"); return this; } @@ -76,8 +75,8 @@ class Messenger extends EventEmitter { * @return {Messenger} this */ sendToAgent(action, data) { - debug('[%s] send %s with %j to all agent', this.pid, action, data); - this.send(action, data, 'agent'); + debug("[%s] send %s with %j to all agent", this.pid, action, data); + this.send(action, data, "agent"); return this; } @@ -95,7 +94,7 @@ class Messenger extends EventEmitter { let agent; let opposite; - if (egg.type === 'application') { + if (egg.type === "application") { application = egg; agent = egg.agent; opposite = agent; @@ -104,15 +103,15 @@ class Messenger extends EventEmitter { application = egg.application; opposite = application; } - if (!to) to = egg.type === 'application' ? 'agent' : 'application'; + if (!to) to = egg.type === "application" ? "agent" : "application"; - if (application && application.messenger && (to === 'application' || to === 'both')) { + if (application && application.messenger && (to === "application" || to === "both")) { application.messenger._onMessage({ action, data }); } - if (agent && agent.messenger && (to === 'agent' || to === 'both')) { + if (agent && agent.messenger && (to === "agent" || to === "both")) { agent.messenger._onMessage({ action, data }); } - if (opposite && opposite.messenger && to === 'opposite') { + if (opposite && opposite.messenger && to === "opposite") { opposite.messenger._onMessage({ action, data }); } }); @@ -122,7 +121,7 @@ class Messenger extends EventEmitter { _onMessage(message) { if (message && is.string(message.action)) { - debug('[%s] got message %s with %j', this.pid, message.action, message.data); + debug("[%s] got message %s with %j", this.pid, message.action, message.data); this.emit(message.action, message.data); } } diff --git a/lib/core/singleton.js b/lib/core/singleton.js index 7931557e73..b70166ec4e 100644 --- a/lib/core/singleton.js +++ b/lib/core/singleton.js @@ -1,13 +1,13 @@ -'use strict'; +"use strict"; -const assert = require('node:assert'); -const is = require('is-type-of'); +const assert = require("node:assert"); +const is = require("is-type-of"); class Singleton { constructor(options = {}) { - assert(options.name, '[egg:singleton] Singleton#constructor options.name is required'); - assert(options.app, '[egg:singleton] Singleton#constructor options.app is required'); - assert(options.create, '[egg:singleton] Singleton#constructor options.create is required'); + assert(options.name, "[egg:singleton] Singleton#constructor options.name is required"); + assert(options.app, "[egg:singleton] Singleton#constructor options.app is required"); + assert(options.create, "[egg:singleton] Singleton#constructor options.create is required"); assert(!options.app[options.name], `${options.name} is already exists in app`); this.clients = new Map(); this.app = options.app; @@ -23,8 +23,10 @@ class Singleton { initSync() { const options = this.options; - assert(!(options.client && options.clients), - `egg:singleton ${this.name} can not set options.client and options.clients both`); + assert( + !(options.client && options.clients), + `egg:singleton ${this.name} can not set options.client and options.clients both`, + ); // alias app[name] as client, but still support createInstance method if (options.client) { @@ -36,7 +38,7 @@ class Singleton { // multi client, use app[name].getInstance(id) if (options.clients) { - Object.keys(options.clients).forEach(id => { + Object.keys(options.clients).forEach((id) => { const client = this.createInstance(options.clients[id], id); this.clients.set(id, client); }); @@ -50,8 +52,10 @@ class Singleton { async initAsync() { const options = this.options; - assert(!(options.client && options.clients), - `egg:singleton ${this.name} can not set options.client and options.clients both`); + assert( + !(options.client && options.clients), + `egg:singleton ${this.name} can not set options.client and options.clients both`, + ); // alias app[name] as client, but still support createInstance method if (options.client) { @@ -63,10 +67,13 @@ class Singleton { // multi client, use app[name].getInstance(id) if (options.clients) { - await Promise.all(Object.keys(options.clients).map(id => { - return this.createInstanceAsync(options.clients[id], id) - .then(client => this.clients.set(id, client)); - })); + await Promise.all( + Object.keys(options.clients).map((id) => { + return this.createInstanceAsync(options.clients[id], id).then((client) => + this.clients.set(id, client), + ); + }), + ); this.app[this.name] = this; return; } @@ -86,8 +93,10 @@ class Singleton { createInstance(config, clientName) { // async creator only support createInstanceAsync - assert(!is.asyncFunction(this.create), - `egg:singleton ${this.name} only support create asynchronous, please use createInstanceAsync`); + assert( + !is.asyncFunction(this.create), + `egg:singleton ${this.name} only support create asynchronous, please use createInstanceAsync`, + ); // options.default will be merge in to options.clients[id] config = Object.assign({}, this.options.default, config); return this.create(config, this.app, clientName); @@ -100,20 +109,26 @@ class Singleton { } _extendDynamicMethods(client) { - assert(!client.createInstance, 'singleton instance should not have createInstance method'); - assert(!client.createInstanceAsync, 'singleton instance should not have createInstanceAsync method'); + assert(!client.createInstance, "singleton instance should not have createInstance method"); + assert( + !client.createInstanceAsync, + "singleton instance should not have createInstanceAsync method", + ); try { let extendable = client; // Object.preventExtensions() or Object.freeze() if (!Object.isExtensible(client) || Object.isFrozen(client)) { - // eslint-disable-next-line no-proto + // oxlint-disable-next-line no-proto extendable = client.__proto__ || client; } extendable.createInstance = this.createInstance.bind(this); extendable.createInstanceAsync = this.createInstanceAsync.bind(this); } catch { - this.app.logger.warn('egg:singleton %s dynamic create is disabled because of client is unextensible', this.name); + this.app.logger.warn( + "egg:singleton %s dynamic create is disabled because of client is unextensible", + this.name, + ); } } } diff --git a/lib/core/utils.js b/lib/core/utils.js index 657d3952f2..e747261bf0 100644 --- a/lib/core/utils.js +++ b/lib/core/utils.js @@ -1,8 +1,8 @@ -'use strict'; +"use strict"; -const util = require('node:util'); -const is = require('is-type-of'); -const URL = require('node:url').URL; +const util = require("node:util"); +const is = require("is-type-of"); +const URL = require("node:url").URL; module.exports = { convertObject, @@ -12,17 +12,23 @@ module.exports = { function convertObject(obj, ignore, ignoreKeyPaths) { if (!is.array(ignore)) { - ignore = [ ignore ]; + ignore = [ignore]; } if (!is.array(ignoreKeyPaths)) { - ignoreKeyPaths = ignoreKeyPaths ? [ ignoreKeyPaths ] : []; + ignoreKeyPaths = ignoreKeyPaths ? [ignoreKeyPaths] : []; } - _convertObject(obj, ignore, ignoreKeyPaths, ''); + _convertObject(obj, ignore, ignoreKeyPaths, ""); } function _convertObject(obj, ignore, ignoreKeyPaths, keyPath) { for (const key of Object.keys(obj)) { - obj[key] = convertValue(key, obj[key], ignore, ignoreKeyPaths, keyPath ? `${keyPath}.${key}` : key); + obj[key] = convertValue( + key, + obj[key], + ignore, + ignoreKeyPaths, + keyPath ? `${keyPath}.${key}` : key, + ); } return obj; } @@ -56,13 +62,13 @@ function convertValue(key, value, ignore, ignoreKeyPaths, keyPath) { // o = {} if (Object.getPrototypeOf(value) === Object.prototype) { if (hitKeyPath) { - return ''; + return ""; } return _convertObject(value, ignore, ignoreKeyPaths, keyPath); } // support class - const name = value.name || 'anonymous'; + const name = value.name || "anonymous"; if (is.class(value)) { return ``; } @@ -100,14 +106,14 @@ function safeParseURL(url) { * - Allows overriding properties on the proxy target (overlay) to take effect. * - Delegates everything else to the real object. * - * @param {Object} options + * @param {Object} options - proxy configuration options * @param {Function} options.createReal Create the real object (lazy) - * @param {boolean} [options.bindFunctions=true] Bind real methods to the real object - * @return {Proxy} + * @param {boolean} [options.bindFunctions] Bind real methods to the real object, default is true + * @return {Proxy} the transparent proxy instance */ function createTransparentProxy({ createReal, bindFunctions = true }) { - if (typeof createReal !== 'function') { - throw new TypeError('createReal must be a function'); + if (typeof createReal !== "function") { + throw new TypeError("createReal must be a function"); } let real = null; @@ -128,81 +134,86 @@ function createTransparentProxy({ createReal, bindFunctions = true }) { } }; - return new Proxy({}, { - get(target, prop, receiver) { - init(); - // Check if property is defined on proxy target (monkeypatch overlay) - if (Object.getOwnPropertyDescriptor(target, prop)) { - return Reflect.get(target, prop, receiver); - } - const value = real[prop]; - if (bindFunctions && typeof value === 'function') { - return value.bind(real); - } - return value; + return new Proxy( + {}, + { + get(target, prop, receiver) { + init(); + // Check if property is defined on proxy target (monkeypatch overlay) + if (Object.getOwnPropertyDescriptor(target, prop)) { + return Reflect.get(target, prop, receiver); + } + const value = real[prop]; + if (bindFunctions && typeof value === "function") { + return value.bind(real); + } + return value; + }, + + set(target, prop, value, receiver) { + init(); + if (Object.getOwnPropertyDescriptor(target, prop)) { + return Reflect.set(target, prop, value, receiver); + } + return Reflect.set(real, prop, value); + }, + + has(target, prop) { + init(); + return prop in target || prop in real; + }, + + ownKeys(target) { + init(); + const keys = new Set([...Reflect.ownKeys(real), ...Reflect.ownKeys(target)]); + return Array.from(keys); + }, + + getOwnPropertyDescriptor(target, prop) { + init(); + return ( + Object.getOwnPropertyDescriptor(target, prop) || + Object.getOwnPropertyDescriptor(real, prop) + ); + }, + + deleteProperty(target, prop) { + init(); + if (Object.getOwnPropertyDescriptor(target, prop)) { + return delete target[prop]; + } + return delete real[prop]; + }, + + getPrototypeOf() { + init(); + return Object.getPrototypeOf(real); + }, + + setPrototypeOf(_target, proto) { + init(); + return Reflect.setPrototypeOf(real, proto); + }, + + isExtensible() { + init(); + return Reflect.isExtensible(real); + }, + + preventExtensions(target) { + init(); + // Must also prevent extensions on target to satisfy Proxy invariants + const result = Reflect.preventExtensions(real); + if (result) { + Reflect.preventExtensions(target); + } + return result; + }, + + defineProperty(target, prop, descriptor) { + // Used by monkeypatch libs: keep overrides on proxy target (overlay layer). + return Reflect.defineProperty(target, prop, descriptor); + }, }, - - set(target, prop, value, receiver) { - init(); - if (Object.getOwnPropertyDescriptor(target, prop)) { - return Reflect.set(target, prop, value, receiver); - } - return Reflect.set(real, prop, value); - }, - - has(target, prop) { - init(); - return prop in target || prop in real; - }, - - ownKeys(target) { - init(); - const keys = new Set([ ...Reflect.ownKeys(real), ...Reflect.ownKeys(target) ]); - return Array.from(keys); - }, - - getOwnPropertyDescriptor(target, prop) { - init(); - return Object.getOwnPropertyDescriptor(target, prop) - || Object.getOwnPropertyDescriptor(real, prop); - }, - - deleteProperty(target, prop) { - init(); - if (Object.getOwnPropertyDescriptor(target, prop)) { - return delete target[prop]; - } - return delete real[prop]; - }, - - getPrototypeOf() { - init(); - return Object.getPrototypeOf(real); - }, - - setPrototypeOf(_target, proto) { - init(); - return Reflect.setPrototypeOf(real, proto); - }, - - isExtensible() { - init(); - return Reflect.isExtensible(real); - }, - - preventExtensions(target) { - init(); - // Must also prevent extensions on target to satisfy Proxy invariants - const result = Reflect.preventExtensions(real); - if (result) { - Reflect.preventExtensions(target); - } - return result; - }, - - defineProperty(target, prop, descriptor) { - // Used by monkeypatch libs: keep overrides on proxy target (overlay layer). - return Reflect.defineProperty(target, prop, descriptor); - }, - }); + ); } diff --git a/lib/egg.js b/lib/egg.js index 4b462d8ec5..ffa5625c01 100644 --- a/lib/egg.js +++ b/lib/egg.js @@ -1,30 +1,30 @@ -const { performance } = require('node:perf_hooks'); -const path = require('node:path'); -const fs = require('node:fs'); -const ms = require('ms'); -const http = require('node:http'); -const EggCore = require('egg-core').EggCore; -const cluster = require('cluster-client'); -const extend = require('extend2'); -const ContextLogger = require('egg-logger').EggContextLogger; -const ContextCookies = require('egg-cookies'); -const CircularJSON = require('circular-json-for-egg'); -const ContextHttpClient = require('./core/context_httpclient'); -const Messenger = require('./core/messenger'); -const DNSCacheHttpClient = require('./core/dnscache_httpclient'); -const HttpClient = require('./core/httpclient'); -const HttpClientNext = require('./core/httpclient_next'); -const { FetchFactory, safeFetch, fetch } = require('./core/fetch_factory'); -const createLoggers = require('./core/logger'); -const Singleton = require('./core/singleton'); -const utils = require('./core/utils'); -const BaseContextClass = require('./core/base_context_class'); -const BaseHookClass = require('./core/base_hook_class'); - -const HTTPCLIENT = Symbol('EggApplication#httpclient'); -const LOGGERS = Symbol('EggApplication#loggers'); -const EGG_PATH = Symbol.for('egg#eggPath'); -const CLUSTER_CLIENTS = Symbol.for('egg#clusterClients'); +const { performance } = require("node:perf_hooks"); +const path = require("node:path"); +const fs = require("node:fs"); +const ms = require("ms"); +const http = require("node:http"); +const EggCore = require("egg-core").EggCore; +const cluster = require("cluster-client"); +const extend = require("extend2"); +const ContextLogger = require("egg-logger").EggContextLogger; +const ContextCookies = require("egg-cookies"); +const CircularJSON = require("circular-json-for-egg"); +const ContextHttpClient = require("./core/context_httpclient"); +const Messenger = require("./core/messenger"); +const DNSCacheHttpClient = require("./core/dnscache_httpclient"); +const HttpClient = require("./core/httpclient"); +const HttpClientNext = require("./core/httpclient_next"); +const { FetchFactory, safeFetch, fetch } = require("./core/fetch_factory"); +const createLoggers = require("./core/logger"); +const Singleton = require("./core/singleton"); +const utils = require("./core/utils"); +const BaseContextClass = require("./core/base_context_class"); +const BaseHookClass = require("./core/base_hook_class"); + +const HTTPCLIENT = Symbol("EggApplication#httpclient"); +const LOGGERS = Symbol("EggApplication#loggers"); +const EGG_PATH = Symbol.for("egg#eggPath"); +const CLUSTER_CLIENTS = Symbol.for("egg#clusterClients"); /** * Based on koa's Application @@ -33,7 +33,6 @@ const CLUSTER_CLIENTS = Symbol.for('egg#clusterClients'); * @augments EggCore */ class EggApplication extends EggCore { - /** * @class * @param {Object} options @@ -43,7 +42,7 @@ class EggApplication extends EggCore { * - {String} [mode] - process mode, can be cluster / single, default is `cluster` */ constructor(options = {}) { - options.mode = options.mode || 'cluster'; + options.mode = options.mode || "cluster"; super(options); // export context base classes, let framework can impl sub class and over context extend easily. @@ -68,27 +67,32 @@ class EggApplication extends EggCore { // trigger `serverDidReady` hook when all the app workers // and agent worker are ready - this.messenger.once('egg-ready', () => { + this.messenger.once("egg-ready", () => { this.lifecycle.triggerServerDidReady(); }); // dump config after ready, ensure all the modifications during start will be recorded // make sure dumpConfig is the last ready callback - this.ready(() => process.nextTick(() => { - const dumpStartTime = Date.now(); - this.dumpConfig(); - this.dumpTiming(); - this.coreLogger.info('[egg:core] dump config after ready, %s', ms(Date.now() - dumpStartTime)); - })); + this.ready(() => + process.nextTick(() => { + const dumpStartTime = Date.now(); + this.dumpConfig(); + this.dumpTiming(); + this.coreLogger.info( + "[egg:core] dump config after ready, %s", + ms(Date.now() - dumpStartTime), + ); + }), + ); this._setupTimeoutTimer(); - this.console.info('[egg:core] App root: %s', this.baseDir); - this.console.info('[egg:core] All *.log files save on %j', this.config.logger.dir); - this.console.info('[egg:core] Loaded enabled plugin %j', this.loader.orderPlugins); + this.console.info("[egg:core] App root: %s", this.baseDir); + this.console.info("[egg:core] All *.log files save on %j", this.config.logger.dir); + this.console.info("[egg:core] Loaded enabled plugin %j", this.loader.orderPlugins); // Listen the error that promise had not catch, then log it in common-error this._unhandledRejectionHandler = this._unhandledRejectionHandler.bind(this); - process.on('unhandledRejection', this._unhandledRejectionHandler); + process.on("unhandledRejection", this._unhandledRejectionHandler); this[CLUSTER_CLIENTS] = []; @@ -112,14 +116,15 @@ class EggApplication extends EggCore { */ this.cluster = (clientClass, options) => { options = Object.assign({}, this.config.clusterClient, options, { - singleMode: this.options.mode === 'single', + singleMode: this.options.mode === "single", // cluster need a port that can't conflict on the environment port: this.options.clusterPort, // agent worker is leader, app workers are follower - isLeader: this.type === 'agent', + isLeader: this.type === "agent", logger: this.coreLogger, // debug mode does not check heartbeat - isCheckHeartbeat: this.config.env === 'prod' ? true : require('node:inspector').url() === undefined, + isCheckHeartbeat: + this.config.env === "prod" ? true : require("node:inspector").url() === undefined, }); const client = cluster(clientClass, options); this._patchClusterClient(client); @@ -129,7 +134,7 @@ class EggApplication extends EggCore { // register close function this.beforeClose(async () => { // single process mode will close agent before app close - if (this.type === 'application' && this.options.mode === 'single') { + if (this.type === "application" && this.options.mode === "single") { await this.agent.close(); } @@ -137,7 +142,7 @@ class EggApplication extends EggCore { logger.close(); } this.messenger.close(); - process.removeListener('unhandledRejection', this._unhandledRejectionHandler); + process.removeListener("unhandledRejection", this._unhandledRejectionHandler); }); /** @@ -225,20 +230,16 @@ class EggApplication extends EggCore { } } - delegate(res, this, [ - 'name', - 'baseDir', - 'subdomainOffset', - ]); + delegate(res, this, ["name", "baseDir", "subdomainOffset"]); abbr(res, this, [ - 'config', - 'controller', - 'httpclient', - 'loggers', - 'middlewares', - 'router', - 'serviceClasses', + "config", + "controller", + "httpclient", + "loggers", + "middlewares", + "router", + "serviceClasses", ]); return res; @@ -372,7 +373,7 @@ class EggApplication extends EggCore { * @since 1.0.0 */ get logger() { - return this.getLogger('logger'); + return this.getLogger("logger"); } /** @@ -381,7 +382,7 @@ class EggApplication extends EggCore { * @since 1.0.0 */ get coreLogger() { - return this.getLogger('coreLogger'); + return this.getLogger("coreLogger"); } _unhandledRejectionHandler(err) { @@ -397,8 +398,8 @@ class EggApplication extends EggCore { err = newError; } /* istanbul ignore else */ - if (err.name === 'Error') { - err.name = 'unhandledRejectionError'; + if (err.name === "Error") { + err.name = "unhandledRejectionError"; } this.coreLogger.error(err); } @@ -424,7 +425,11 @@ class EggApplication extends EggCore { ignoreKeyPaths = {}; } - const json = extend(true, {}, { config: this.config, plugins: this.loader.allPlugins, appInfo: this.loader.appInfo }); + const json = extend( + true, + {}, + { config: this.config, plugins: this.loader.allPlugins, appInfo: this.loader.appInfo }, + ); utils.convertObject(json, ignoreList, ignoreKeyPaths ? Object.keys(ignoreKeyPaths) : []); return { config: json, @@ -470,8 +475,12 @@ class EggApplication extends EggCore { for (const item of items) { // ignore #0 name: Process Start if (item.index > 0 && item.duration >= this.config.dump.timing.slowBootActionMinDuration) { - this.coreLogger.warn('[egg:core][slow-boot-action] #%d %dms, name: %s', - item.index, item.duration, item.name); + this.coreLogger.warn( + "[egg:core][slow-boot-action] #%d %dms, name: %s", + item.index, + item.duration, + item.name, + ); } } } catch (err) { @@ -480,13 +489,15 @@ class EggApplication extends EggCore { } get [EGG_PATH]() { - return path.join(__dirname, '..'); + return path.join(__dirname, ".."); } _setupTimeoutTimer() { const startTimeoutTimer = setTimeout(() => { this.coreLogger.error(this.timing.toString()); - this.coreLogger.error(`${this.type} still doesn't ready after ${this.config.workerStartTimeout} ms.`); + this.coreLogger.error( + `${this.type} still doesn't ready after ${this.config.workerStartTimeout} ms.`, + ); // log unfinished const items = this.timing.toJSON(); for (const item of items) { @@ -494,7 +505,7 @@ class EggApplication extends EggCore { this.coreLogger.error(`unfinished timing item: ${CircularJSON.stringify(item)}`); } this.coreLogger.error(`check run/${this.type}_timing_${process.pid}.json for more details.`); - this.emit('startTimeout'); + this.emit("startTimeout"); this.dumpConfig(); this.dumpTiming(); }, this.config.workerStartTimeout); @@ -506,21 +517,24 @@ class EggApplication extends EggCore { * @deprecated */ get env() { - this.deprecate('please use app.config.env instead'); + this.deprecate("please use app.config.env instead"); return this.config.env; } - /* eslint no-empty-function: off */ - set env(_) { } + set env(_) { + // no-op, deprecated setter + } /** * app.proxy delegate app.config.proxy * @deprecated */ get proxy() { - this.deprecate('please use app.config.proxy instead'); + this.deprecate("please use app.config.proxy instead"); return this.config.proxy; } - set proxy(_) { } + set proxy(_) { + // no-op, deprecated setter + } /** * create a singleton instance @@ -561,26 +575,26 @@ class EggApplication extends EggCore { createAnonymousContext(req) { const request = { headers: { - host: '127.0.0.1', - 'x-forwarded-for': '127.0.0.1', + host: "127.0.0.1", + "x-forwarded-for": "127.0.0.1", }, query: {}, - querystring: '', - host: '127.0.0.1', - hostname: '127.0.0.1', - protocol: 'http', - secure: 'false', - method: 'GET', - url: '/', - path: '/', + querystring: "", + host: "127.0.0.1", + hostname: "127.0.0.1", + protocol: "http", + secure: "false", + method: "GET", + url: "/", + path: "/", socket: { - remoteAddress: '127.0.0.1', + remoteAddress: "127.0.0.1", remotePort: 7001, }, }; if (req) { for (const key in req) { - if (key === 'headers' || key === 'query' || key === 'socket') { + if (key === "headers" || key === "query" || key === "socket") { Object.assign(request[key], req[key]); } else { request[key] = req[key]; @@ -601,8 +615,8 @@ class EggApplication extends EggCore { createContext(req, res) { const app = this; const context = Object.create(app.context); - const request = context.request = Object.create(app.request); - const response = context.response = Object.create(app.response); + const request = (context.request = Object.create(app.request)); + const response = (context.response = Object.create(app.response)); context.app = request.app = response.app = app; context.req = request.req = response.req = req; context.res = request.res = response.res = res; @@ -627,7 +641,6 @@ class EggApplication extends EggCore { } return context; } - } module.exports = EggApplication; diff --git a/lib/loader/agent_worker_loader.js b/lib/loader/agent_worker_loader.js index abf4c3bde1..b1b4fac89b 100644 --- a/lib/loader/agent_worker_loader.js +++ b/lib/loader/agent_worker_loader.js @@ -1,13 +1,12 @@ -'use strict'; +"use strict"; -const EggLoader = require('egg-core').EggLoader; +const EggLoader = require("egg-core").EggLoader; /** * Agent worker process loader * @see https://github.com/eggjs/egg-loader */ class AgentWorkerLoader extends EggLoader { - /** * loadPlugin first, then loadConfig */ diff --git a/lib/loader/app_worker_loader.js b/lib/loader/app_worker_loader.js index f2de253de3..b9dc438c4e 100644 --- a/lib/loader/app_worker_loader.js +++ b/lib/loader/app_worker_loader.js @@ -1,13 +1,12 @@ -'use strict'; +"use strict"; -const EggLoader = require('egg-core').EggLoader; +const EggLoader = require("egg-core").EggLoader; /** * App worker process Loader, will load plugins * @see https://github.com/eggjs/egg-loader */ class AppWorkerLoader extends EggLoader { - /** * loadPlugin first, then loadConfig * @since 1.0.0 @@ -42,7 +41,6 @@ class AppWorkerLoader extends EggLoader { // app this.loadRouter(); // Depend on controllers } - } module.exports = AppWorkerLoader; diff --git a/lib/loader/index.js b/lib/loader/index.js index 8c4e7c979d..8a275b31fd 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -1,5 +1,5 @@ -'use strict'; +"use strict"; -exports.EggLoader = require('egg-core').EggLoader; -exports.AppWorkerLoader = require('./app_worker_loader'); -exports.AgentWorkerLoader = require('./agent_worker_loader'); +exports.EggLoader = require("egg-core").EggLoader; +exports.AppWorkerLoader = require("./app_worker_loader"); +exports.AgentWorkerLoader = require("./agent_worker_loader"); diff --git a/lib/start.js b/lib/start.js index 28dde70ab3..83fae78274 100644 --- a/lib/start.js +++ b/lib/start.js @@ -1,16 +1,15 @@ -'use strict'; +"use strict"; -const path = require('node:path'); +const path = require("node:path"); module.exports = async (options = {}) => { - options.baseDir = options.baseDir || process.cwd(); - options.mode = 'single'; + options.mode = "single"; // get agent from options.framework and package.egg.framework if (!options.framework) { try { - options.framework = require(path.join(options.baseDir, 'package.json')).egg.framework; + options.framework = require(path.join(options.baseDir, "package.json")).egg.framework; } catch { // ignore } @@ -21,8 +20,8 @@ module.exports = async (options = {}) => { Agent = require(options.framework).Agent; Application = require(options.framework).Application; } else { - Application = require('./application'); - Agent = require('./agent'); + Application = require("./application"); + Agent = require("./agent"); } const agent = new Agent(Object.assign({}, options)); @@ -33,7 +32,7 @@ module.exports = async (options = {}) => { await application.ready(); // emit egg-ready message in agent and application - application.messenger.broadcast('egg-ready'); + application.messenger.broadcast("egg-ready"); return application; }; diff --git a/package.json b/package.json index 0fa5e7e782..09f883d435 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,54 @@ { "name": "egg", "version": "3.34.0", - "publishConfig": { - "tag": "release-3.x", - "access": "public" - }, "description": "A web framework's framework for Node.js", "keywords": [ - "web", "app", - "http", "application", + "egg", "framework", - "middleware", + "http", "koa", - "egg" + "middleware", + "web" + ], + "homepage": "https://github.com/eggjs/egg", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/eggjs/egg.git" + }, + "files": [ + "index.js", + "lib", + "app", + "config", + "agent.js", + "index.d.ts" ], + "main": "index.js", + "types": "index.d.ts", + "publishConfig": { + "access": "public", + "tag": "release-3.x" + }, + "scripts": { + "lint": "vp lint app config lib test *.js", + "tsd": "tsd", + "test": "npm run lint -- --fix && npm run tsd && npm run test-local", + "test-local": "egg-bin test --ts false", + "test-local-changed": "egg-bin test --changed --ts false", + "cov": "egg-bin cov --timeout 100000 --ts false", + "ci": "npm run lint && npm run tsd && npm run cov", + "site:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider APP_ROOT=./site dumi dev", + "site:devWithNode14-16": "cross-env APP_ROOT=./site dumi dev", + "site:build": "cross-env NODE_OPTIONS=--openssl-legacy-provider APP_ROOT=./site dumi build", + "site:buildWithNode14-16": "cross-env APP_ROOT=./site dumi build", + "site:prettier": "prettier --config site/.prettierrc --ignore-path site/.prettierignore --write \"site/**/*.{js,jsx,tsx,ts,less,md,json}\"", + "puml": "puml . --dest ./site", + "commits": "./scripts/commits.sh", + "prepare": "vp config" + }, "dependencies": { "@types/accepts": "^1.3.5", "@types/koa": "^2.13.5", @@ -62,6 +95,9 @@ }, "devDependencies": { "@eggjs/tsconfig": "^1.1.0", + "@eslint/compat": "^2.0.3", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "^9.39.4", "@types/node": "^20.1.2", "@umijs/preset-react": "^2.1.6", "address": "^1.2.1", @@ -76,13 +112,12 @@ "egg-plugin-puml": "^2.4.0", "egg-tracer": "^2.0.0", "egg-view-nunjucks": "^2.3.0", - "@eslint/compat": "^2.0.3", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "^9.39.4", - "eslint": "^9.39.4", "eslint-config-egg": "^14.1.0", - "globals": "^16.2.0", + "eslint-plugin-eggache": "^2.0.0", + "eslint-plugin-jsdoc": "^62.7.1", + "eslint-plugin-node": "^11.1.0", "formstream": "^1.1.1", + "globals": "^16.2.0", "jsdoc": "^3.6.11", "koa": "^2.13.4", "koa-static": "^5.0.0", @@ -99,41 +134,17 @@ "ts-node": "^10.9.1", "tsd": "^0.28.1", "typescript": "^5.0.4", - "umi": "^3.5.36" - }, - "main": "index.js", - "types": "index.d.ts", - "files": [ - "index.js", - "lib", - "app", - "config", - "agent.js", - "index.d.ts" - ], - "scripts": { - "lint": "eslint app config lib test *.js", - "tsd": "tsd", - "test": "npm run lint -- --fix && npm run tsd && npm run test-local", - "test-local": "egg-bin test --ts false", - "test-local-changed": "egg-bin test --changed --ts false", - "cov": "egg-bin cov --timeout 100000 --ts false", - "ci": "npm run lint && npm run tsd && npm run cov", - "site:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider APP_ROOT=./site dumi dev", - "site:devWithNode14-16": "cross-env APP_ROOT=./site dumi dev", - "site:build": "cross-env NODE_OPTIONS=--openssl-legacy-provider APP_ROOT=./site dumi build", - "site:buildWithNode14-16": "cross-env APP_ROOT=./site dumi build", - "site:prettier": "prettier --config site/.prettierrc --ignore-path site/.prettierignore --write \"site/**/*.{js,jsx,tsx,ts,less,md,json}\"", - "puml": "puml . --dest ./site", - "commits": "./scripts/commits.sh" - }, - "homepage": "https://github.com/eggjs/egg", - "repository": { - "type": "git", - "url": "git+https://github.com/eggjs/egg.git" + "umi": "^3.5.36", + "vite-plus": "latest" }, "engines": { "node": ">= 14.20.0" }, - "license": "MIT" + "packageManager": "pnpm@10.31.0", + "pnpm": { + "overrides": { + "vite": "npm:@voidzero-dev/vite-plus-core@latest", + "vitest": "npm:@voidzero-dev/vite-plus-test@latest" + } + } } diff --git a/site/app.ts b/site/app.ts index 2b5d6c2152..910775fbcc 100644 --- a/site/app.ts +++ b/site/app.ts @@ -1,20 +1,20 @@ // @ts-ignore -import { history, Route } from 'umi'; +import { history, Route } from "umi"; export function onRouteChange(props: any) { const { location }: RouterChangeProps = props; let pathname = location.pathname; - if (pathname.startsWith('/en')) { - pathname = pathname.replace('/en', ''); - pathname = pathname.replace('.html', ''); + if (pathname.startsWith("/en")) { + pathname = pathname.replace("/en", ""); + pathname = pathname.replace(".html", ""); history.push(pathname); } - if (pathname.startsWith('/zh-cn')) { - pathname = pathname.replace('zh-cn', 'zh-CN'); - pathname = pathname.replace('.html', ''); + if (pathname.startsWith("/zh-cn")) { + pathname = pathname.replace("zh-cn", "zh-CN"); + pathname = pathname.replace(".html", ""); history.push(pathname); } } diff --git a/site/config/config.ts b/site/config/config.ts index 649551afb0..70228f2081 100644 --- a/site/config/config.ts +++ b/site/config/config.ts @@ -1,13 +1,13 @@ -import { defineConfig } from 'dumi'; +import { defineConfig } from "dumi"; export default defineConfig({ - mode: 'site', - title: 'Egg', + mode: "site", + title: "Egg", - description: 'Born to build better enterprise frameworks and apps', + description: "Born to build better enterprise frameworks and apps", - logo: '/logo.svg', - favicon: '/favicon.png', + logo: "/logo.svg", + favicon: "/favicon.png", // algolia: { // apiKey: '1561de31a86f79507ea00cdb54ce647c', @@ -15,60 +15,60 @@ export default defineConfig({ // }, theme: { - '@c-primary': '#22ab28', + "@c-primary": "#22ab28", }, exportStatic: {}, sitemap: { - hostname: 'https://v3.eggjs.org', + hostname: "https://v3.eggjs.org", }, navs: { - 'en-US': [ + "en-US": [ null, { - title: 'GitHub', - path: 'https://github.com/eggjs/egg', + title: "GitHub", + path: "https://github.com/eggjs/egg", }, { - title: 'Release', - path: 'https://github.com/eggjs/egg/releases', + title: "Release", + path: "https://github.com/eggjs/egg/releases", }, { - title: 'Plugins', - path: 'https://github.com/search?q=topic%3Aegg-plugin&type=Repositories', + title: "Plugins", + path: "https://github.com/search?q=topic%3Aegg-plugin&type=Repositories", }, { - title: 'v3.x', - path: 'https://v3.eggjs.org', + title: "v3.x", + path: "https://v3.eggjs.org", }, { - title: 'v4.x', - path: 'https://eggjs.org', + title: "v4.x", + path: "https://eggjs.org", }, ], - 'zh-CN': [ + "zh-CN": [ null, { - title: 'GitHub', - path: 'https://github.com/eggjs/egg', + title: "GitHub", + path: "https://github.com/eggjs/egg", }, { - title: '发布日志', - path: 'https://github.com/eggjs/egg/releases', + title: "发布日志", + path: "https://github.com/eggjs/egg/releases", }, { - title: '插件列表', - path: 'https://github.com/search?q=topic%3Aegg-plugin&type=Repositories', + title: "插件列表", + path: "https://github.com/search?q=topic%3Aegg-plugin&type=Repositories", }, { - title: 'v3.x', - path: 'https://v3.eggjs.org', + title: "v3.x", + path: "https://v3.eggjs.org", }, { - title: 'v4.x', - path: 'https://eggjs.org', + title: "v4.x", + path: "https://eggjs.org", }, ], }, @@ -76,49 +76,49 @@ export default defineConfig({ themeConfig: { links: [ { - title: 'Resources', + title: "Resources", list: [ { - name: 'Egg', - url: 'https://github.com/eggjs/egg', + name: "Egg", + url: "https://github.com/eggjs/egg", }, { - name: 'Organization', - url: 'https://github.com/eggjs', + name: "Organization", + url: "https://github.com/eggjs", }, ], }, { - title: 'XTech', + title: "XTech", list: [ - { name: 'EggJS - 企业级 Node.js 开发框架', url: 'https://eggjs.org' }, - { name: 'Ant Design - UI 体系', url: 'https://ant.design' }, - { name: 'AntV - 数据可视化', url: 'https://antv.vision' }, + { name: "EggJS - 企业级 Node.js 开发框架", url: "https://eggjs.org" }, + { name: "Ant Design - UI 体系", url: "https://ant.design" }, + { name: "AntV - 数据可视化", url: "https://antv.vision" }, { - name: '语雀 - 知识创作与分享工具', - url: 'https://www.yuque.com', + name: "语雀 - 知识创作与分享工具", + url: "https://www.yuque.com", }, ], }, { - title: 'Community', + title: "Community", list: [ - { name: 'Artus.js 官网', url: 'https://artusjs.org' }, - { name: 'CNode 社区', url: 'https://cnodejs.org/' }, - { name: 'Node.js 专栏', url: 'https://www.yuque.com/egg/nodejs' }, + { name: "Artus.js 官网", url: "https://artusjs.org" }, + { name: "CNode 社区", url: "https://cnodejs.org/" }, + { name: "Node.js 专栏", url: "https://www.yuque.com/egg/nodejs" }, { - name: '提交反馈', - url: 'https://github.com/eggjs/egg/issues', + name: "提交反馈", + url: "https://github.com/eggjs/egg/issues", }, - { name: '发布日志', url: 'https://github.com/eggjs/egg/releases' }, + { name: "发布日志", url: "https://github.com/eggjs/egg/releases" }, ], }, { - title: 'Egg.js Telegram Channel', + title: "Egg.js Telegram Channel", list: [ { - name: '钉钉', - qrcode: '/img_egg/qrcode_egg_channel.png', + name: "钉钉", + qrcode: "/img_egg/qrcode_egg_channel.png", }, ], }, diff --git a/site/docs/advanced/cluster-client.md b/site/docs/advanced/cluster-client.md index bbe6b834f2..084f21ec03 100644 --- a/site/docs/advanced/cluster-client.md +++ b/site/docs/advanced/cluster-client.md @@ -70,7 +70,7 @@ We abstract the client interface into the following two broad categories, which Client example ```js -const Base = require('sdk-base'); +const Base = require("sdk-base"); class Client extends Base { constructor(options) { @@ -168,14 +168,14 @@ In the following I will use a simple example to introduce how to make a client s ```js // registry_client.js -const URL = require('url'); -const Base = require('sdk-base'); +const URL = require("url"); +const Base = require("sdk-base"); class RegistryClient extends Base { constructor(options) { super({ // Specify a method for asynchronous start - initMethod: 'init', + initMethod: "init", }); this._options = options; this._registered = new Map(); @@ -249,7 +249,7 @@ module.exports = RegistryClient; ```js // agent.js -const RegistryClient = require('registry_client'); +const RegistryClient = require("registry_client"); module.exports = (agent) => { // encapsulate and instantiate RegistryClient @@ -259,7 +259,7 @@ module.exports = (agent) => { agent.beforeStart(async () => { await agent.registryClient.ready(); - agent.coreLogger.info('registry client is ready'); + agent.coreLogger.info("registry client is ready"); }); }; ``` @@ -268,18 +268,18 @@ module.exports = (agent) => { ```js // app.js -const RegistryClient = require('registry_client'); +const RegistryClient = require("registry_client"); module.exports = (app) => { app.registryClient = app.cluster(RegistryClient).create({}); app.beforeStart(async () => { await app.registryClient.ready(); - app.coreLogger.info('registry client is ready'); + app.coreLogger.info("registry client is ready"); // invoke subscribe to subscribe app.registryClient.subscribe( { - dataId: 'demo.DemoService', + dataId: "demo.DemoService", }, (val) => { // ... @@ -288,12 +288,12 @@ module.exports = (app) => { // invoke publish to publsih data app.registryClient.publish({ - dataId: 'demo.DemoService', - publishData: 'xxx', + dataId: "demo.DemoService", + publishData: "xxx", }); // invoke getConfig interface - const res = await app.registryClient.getConfig('demo.DemoService'); + const res = await app.registryClient.getConfig("demo.DemoService"); console.log(res); }); }; @@ -339,7 +339,7 @@ module.exports = (agent) => { agent.mockClient = agent .cluster(MockClient) // delegate sub to logic of subscribe - .delegate('sub', 'subscribe') + .delegate("sub", "subscribe") .create(); agent.beforeStart(async () => { @@ -354,13 +354,13 @@ module.exports = (app) => { app.mockClient = app .cluster(MockClient) // delegate sub to subscribe logic - .delegate('sub', 'subscribe') + .delegate("sub", "subscribe") .create(); app.beforeStart(async () => { await app.mockClient.ready(); - app.sub({ id: 'test-id' }, (val) => { + app.sub({ id: "test-id" }, (val) => { // put your code here }); }); @@ -384,8 +384,8 @@ For example, add a synchronous get method with buffer in the `APIClient` module: ```js // some-client/index.js -const cluster = require('cluster-client'); -const RegistryClient = require('./registry_client'); +const cluster = require("cluster-client"); +const RegistryClient = require("./registry_client"); class APIClient extends Base { constructor(options) { @@ -454,8 +454,8 @@ exports.apiClient = { To make it easy for you to encapsulate `APIClient`, we provide an` APIClientBase` base class in the [cluster-client](https://www.npmjs.com/package/cluster-client) module. Then `APIClient` above can be rewritten as: ```js -const APIClientBase = require('cluster-client').APIClientBase; -const RegistryClient = require('./registry_client'); +const APIClientBase = require("cluster-client").APIClientBase; +const RegistryClient = require("./registry_client"); class APIClient extends APIClientBase { // return the original client class @@ -537,8 +537,8 @@ app.registryClient = app - You can also override the `getter` attribute of `clusterOptions` in `APIClientBase`: ```js -const APIClientBase = require('cluster-client').APIClientBase; -const RegistryClient = require('./registry_client'); +const APIClientBase = require("cluster-client").APIClientBase; +const RegistryClient = require("./registry_client"); class APIClient extends APIClientBase { get DataClient() { diff --git a/site/docs/advanced/cluster-client.zh-CN.md b/site/docs/advanced/cluster-client.zh-CN.md index 9e6ba1a33a..3b460fe474 100644 --- a/site/docs/advanced/cluster-client.zh-CN.md +++ b/site/docs/advanced/cluster-client.zh-CN.md @@ -23,6 +23,7 @@ order: 4 另外,通过 messenger 传递数据效率较低,因为它会通过 Master 来做中转;万一 IPC 通道出现问题,还可能把 Master 进程弄挂。 那么有没有更好的方法呢?答案是肯定的,我们提供了一种新的模式来降低这类客户端封装的复杂度。通过建立 Agent 和 Worker 的 socket 直连,跳过 Master 的中转,Agent 作为对外的门面,维持多个 Worker 进程的共享连接。 + ## 核心思想 - 受到 [Leader/Follower](https://www.dre.vanderbilt.edu/~schmidt/PDF/lf.pdf) 模式的启发。 @@ -56,6 +57,7 @@ win / +------------------+ \ lose | Client | | Follower(Worker2) | +--------+ +-------------------+ ``` + ## 客户端接口类型抽象 我们将客户端接口抽象为以下两大类,这也是对客户端接口的一个规范,对于符合规范的客户端,我们可以自动将其包装为 Leader/Follower 模式。 @@ -69,7 +71,7 @@ win / +------------------+ \ lose 客户端示例 ```js -const Base = require('sdk-base'); +const Base = require("sdk-base"); class Client extends Base { constructor(options) { @@ -108,10 +110,12 @@ class Client extends Base { } } ``` + ## 异常处理 - 如果 Leader 实例“死掉”,将触发新一轮的端口争夺。争夺到端口的实例将被推举为新的 Leader。 - 为了保证 Leader 和 Follower 之间通道的健康,需要引入定时的心跳检查机制。如果 Follower 在固定时间内未发送心跳包,Leader 会将其主动断开,以触发 Follower 的重新初始化。 + ## 协议和调用时序 Leader 和 Follower 通过下面的协议进行数据交换: @@ -157,6 +161,7 @@ Leader 和 Follower 通过下面的协议进行数据交换: | <------------------------------------------------ + | | ``` + ## 具体的使用方法 下面我用一个简单的例子,介绍在框架里面如何让一个客户端支持 Leader/Follower 模式: @@ -165,14 +170,14 @@ Leader 和 Follower 通过下面的协议进行数据交换: ```js // registry_client.js -const URL = require('url'); -const Base = require('sdk-base'); +const URL = require("url"); +const Base = require("sdk-base"); class RegistryClient extends Base { constructor(options) { super({ // 指定异步启动的方法 - initMethod: 'init', + initMethod: "init", }); this._options = options; this._registered = new Map(); @@ -233,7 +238,7 @@ class RegistryClient extends Base { if (changed) { this.emit( key, - this._registered.get(key).map(url => URL.parse(url, true)), + this._registered.get(key).map((url) => URL.parse(url, true)), ); } } @@ -246,9 +251,9 @@ module.exports = RegistryClient; ```js // agent.js -const RegistryClient = require('./registry_client'); +const RegistryClient = require("./registry_client"); -module.exports = agent => { +module.exports = (agent) => { // 对 RegistryClient 进行封装和实例化 agent.registryClient = agent .cluster(RegistryClient) @@ -257,7 +262,7 @@ module.exports = agent => { agent.beforeStart(async () => { await agent.registryClient.ready(); - agent.coreLogger.info('注册客户端已就绪'); + agent.coreLogger.info("注册客户端已就绪"); }); }; ``` @@ -266,32 +271,32 @@ module.exports = agent => { ```js // app.js -const RegistryClient = require('./registry_client'); +const RegistryClient = require("./registry_client"); -module.exports = app => { +module.exports = (app) => { app.registryClient = app.cluster(RegistryClient).create({}); app.beforeStart(async () => { await app.registryClient.ready(); - app.coreLogger.info('注册客户端已就绪'); + app.coreLogger.info("注册客户端已就绪"); // 调用 subscribe 进行订阅 app.registryClient.subscribe( { - dataId: 'demo.DemoService', + dataId: "demo.DemoService", }, - val => { + (val) => { // ... }, ); // 调用 publish 发布数据 app.registryClient.publish({ - dataId: 'demo.DemoService', - publishData: 'xxx', + dataId: "demo.DemoService", + publishData: "xxx", }); // 调用 getConfig 获取配置 - const res = await app.registryClient.getConfig('demo.DemoService'); + const res = await app.registryClient.getConfig("demo.DemoService"); console.log(res); }); }; @@ -305,7 +310,7 @@ module.exports = app => { class MockClient extends Base { constructor(options) { super({ - initMethod: 'init', + initMethod: "init", }); this._options = options; this._registered = new Map(); @@ -333,11 +338,11 @@ class MockClient extends Base { ```js // agent.js -module.exports = agent => { +module.exports = (agent) => { agent.mockClient = agent .cluster(MockClient) // 将 sub 代理到 subscribe - .delegate('sub', 'subscribe') + .delegate("sub", "subscribe") .create(); agent.beforeStart(async () => { @@ -348,17 +353,17 @@ module.exports = agent => { ```js // app.js -module.exports = app => { +module.exports = (app) => { app.mockClient = app .cluster(MockClient) // 将 sub 代理到 subscribe - .delegate('sub', 'subscribe') + .delegate("sub", "subscribe") .create(); app.beforeStart(async () => { await app.mockClient.ready(); - app.mockClient.sub({ id: 'test-id' }, val => { + app.mockClient.sub({ id: "test-id" }, (val) => { // 请把你的代码放在这里 }); }); @@ -382,8 +387,8 @@ module.exports = app => { ```js // some-client/index.js -const cluster = require('cluster-client'); -const RegistryClient = require('./registry_client'); +const cluster = require("cluster-client"); +const RegistryClient = require("./registry_client"); class APIClient extends Base { constructor(options) { @@ -403,7 +408,7 @@ class APIClient extends Base { const subMap = options.subMap; for (const key in subMap) { - this.subscribe(subMap[key], value => { + this.subscribe(subMap[key], (value) => { this._cache[key] = value; }); } @@ -430,8 +435,8 @@ module.exports = APIClient; ```js // app.js 或 agent.js -const APIClient = require('some-client'); // 上文中的模块 -module.exports = app => { +const APIClient = require("some-client"); // 上文中的模块 +module.exports = (app) => { const config = app.config.apiClient; app.apiClient = new APIClient(Object.assign({}, config, { cluster: app.cluster })); app.beforeStart(async () => { @@ -443,18 +448,18 @@ module.exports = app => { exports.apiClient = { subMap: { foo: { - id: '', + id: "", }, // bar... - } + }, }; ``` 为了方便你封装 `APIClient`,在 `cluster-client` 模块中提供了一个 `APIClientBase` 基类,那么上文中的 `APIClient` 可以改写为: ```js -const APIClientBase = require('cluster-client').APIClientBase; -const RegistryClient = require('./registry_client'); +const APIClientBase = require("cluster-client").APIClientBase; +const RegistryClient = require("./registry_client"); class APIClient extends APIClientBase { // 返回原始的客户端类 @@ -500,6 +505,7 @@ class APIClient extends APIClientBase { - `APIClient` - 内部调用 `ClusterClient` 做数据同步,无需关心多进程模型,用户最终使用的模块。API 通过此处暴露,支持同步和异步。 有兴趣的同学可以查看《增强多进程研发模式》讨论过程。 + ## 在框架里面 cluster-client 相关的配置项 ```js @@ -514,10 +520,10 @@ config.clusterClient = { }; ``` -| 配置项 | 类型 | 默认值 | 描述 | -| --------------- | -------- | ------------------ | ------------------------------------------------------------------ | -| responseTimeout | number | 60000(一分钟) | 全局的进程间通讯的超时时长,因为代理接口本身也有超时设置,所以不宜设置太短 | -| transcode | function | 未设置(N/A) | 进程间通讯的序列化方式,默认使用 [serialize-json](https://www.npmjs.com/package/serialize-json),建议不要自行设置 | +| 配置项 | 类型 | 默认值 | 描述 | +| --------------- | -------- | --------------- | ----------------------------------------------------------------------------------------------------------------- | +| responseTimeout | number | 60000(一分钟) | 全局的进程间通讯的超时时长,因为代理接口本身也有超时设置,所以不宜设置太短 | +| transcode | function | 未设置(N/A) | 进程间通讯的序列化方式,默认使用 [serialize-json](https://www.npmjs.com/package/serialize-json),建议不要自行设置 | 上述表格为全局配置方式。如果你想为特定客户端单独设置,可以使用以下方法: @@ -536,8 +542,8 @@ app.registryClient = app - 也可以通过覆盖 `APIClientBase` 的 `clusterOptions` 这个 `getter` 属性。 ```js -const APIClientBase = require('cluster-client').APIClientBase; -const RegistryClient = require('./registry_client'); +const APIClientBase = require("cluster-client").APIClientBase; +const RegistryClient = require("./registry_client"); class APIClient extends APIClientBase { get DataClient() { @@ -554,4 +560,4 @@ class APIClient extends APIClientBase { } module.exports = APIClient; -``` \ No newline at end of file +``` diff --git a/site/docs/advanced/framework.md b/site/docs/advanced/framework.md index 3eb3e8c91f..bb99f7c056 100644 --- a/site/docs/advanced/framework.md +++ b/site/docs/advanced/framework.md @@ -64,16 +64,16 @@ Each of those APIs is required to be implemented almost twice - one for Agent an This is the entry function of Egg's multiprocess launcher, based on [egg-cluster](https://github.com/eggjs/egg-cluster), to start Master, but EggCore running in a single process doesn't invoke this function while Egg does. ```js -const startCluster = require('egg').startCluster; +const startCluster = require("egg").startCluster; startCluster( { // directory of code - baseDir: '/path/to/app', + baseDir: "/path/to/app", // directory of framework - framework: '/path/to/framework', + framework: "/path/to/framework", }, () => { - console.log('app started'); + console.log("app started"); }, ); ``` @@ -145,26 +145,26 @@ Given a triple-layer framework: department level > enterprise level > Egg ```js // enterprise -const Application = require('egg').Application; +const Application = require("egg").Application; class Enterprise extends Application { get [EGG_PATH]() { - return '/path/to/enterprise'; + return "/path/to/enterprise"; } } // Customize Application exports.Application = Enterprise; // department -const Application = require('enterprise').Application; +const Application = require("enterprise").Application; // extend enterprise's Application class department extends Application { get [EGG_PATH]() { - return '/path/to/department'; + return "/path/to/department"; } } // the path of `department` have to be designated as described above -const Application = require('department').Application; +const Application = require("department").Application; const app = new Application(); app.ready(); ``` @@ -177,9 +177,9 @@ Egg's mutilprocess model is composed of Application and Agent. Therefore Agent, ```js // lib/framework.js -const path = require('path'); -const egg = require('egg'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const path = require("path"); +const egg = require("egg"); +const EGG_PATH = Symbol.for("egg#eggPath"); class Application extends egg.Application { get [EGG_PATH]() { @@ -211,9 +211,9 @@ As the same as Egg-Path, Loader exposes itself at `Symbol.for('egg#loader')` to ```js // lib/framework.js -const path = require('path'); -const egg = require('egg'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const path = require("path"); +const egg = require("egg"); +const EGG_PATH = Symbol.for("egg#eggPath"); class YadanAppWorkerLoader extends egg.AppWorkerLoader { load() { @@ -268,13 +268,13 @@ You'd better read [unittest](../core/unittest.md) first, which is similiar to fr Here are some differences between initiation of frameworks. ```js -const mock = require('egg-mock'); -describe('test/index.test.js', () => { +const mock = require("egg-mock"); +describe("test/index.test.js", () => { let app; before(() => { app = mock.app({ // test/fixtures/apps/example - baseDir: 'apps/example', + baseDir: "apps/example", // importent !! Do not miss framework: true, }); @@ -284,8 +284,8 @@ describe('test/index.test.js', () => { after(() => app.close()); afterEach(mock.restore); - it('should success', () => { - return app.httpRequest().get('/').expect(200); + it("should success", () => { + return app.httpRequest().get("/").expect(200); }); }); ``` @@ -301,24 +301,24 @@ describe('test/index.test.js', () => { `mm.app` enables cache as default, which means new envoriment setting would not work once loaded. ```js -const mock = require('egg-mock'); -describe('/test/index.test.js', () => { +const mock = require("egg-mock"); +describe("/test/index.test.js", () => { let app; afterEach(() => app.close()); - it('should test on local', () => { - mock.env('local'); + it("should test on local", () => { + mock.env("local"); app = mock.app({ - baseDir: 'apps/example', + baseDir: "apps/example", framework: true, cache: false, }); return app.ready(); }); - it('should test on prod', () => { - mock.env('prod'); + it("should test on prod", () => { + mock.env("prod"); app = mock.app({ - baseDir: 'apps/example', + baseDir: "apps/example", framework: true, cache: false, }); @@ -334,20 +334,20 @@ Mutilprocess is rarely tested because of the high cost and the unavailability of The option of `mock.cluster` have no difference with `mm.app` while their APIs are totally distinct, however, SuperTest still works. ```js -const mock = require('egg-mock'); -describe('/test/index.test.js', () => { +const mock = require("egg-mock"); +describe("/test/index.test.js", () => { let app; before(() => { app = mock.cluster({ - baseDir: 'apps/example', + baseDir: "apps/example", framework: true, }); return app.ready(); }); after(() => app.close()); afterEach(mock.restore); - it('should success', () => { - return app.httpRequest().get('/').expect(200); + it("should success", () => { + return app.httpRequest().get("/").expect(200); }); }); ``` @@ -355,20 +355,20 @@ describe('/test/index.test.js', () => { Tests of `stdout/stderr` are also avaiable, since `mm.cluster` is based on [coffee](https://github.com/popomore/coffee) in which multiprocess testing is supported. ```js -const mock = require('egg-mock'); -describe('/test/index.test.js', () => { +const mock = require("egg-mock"); +describe("/test/index.test.js", () => { let app; before(() => { app = mock.cluster({ - baseDir: 'apps/example', + baseDir: "apps/example", framework: true, }); return app.ready(); }); after(() => app.close()); - it('should get `started`', () => { + it("should get `started`", () => { // set the expectation of console - app.expect('stdout', /started/); + app.expect("stdout", /started/); }); }); ``` diff --git a/site/docs/advanced/framework.zh-CN.md b/site/docs/advanced/framework.zh-CN.md index 99dc71efac..ed0a4308ba 100644 --- a/site/docs/advanced/framework.zh-CN.md +++ b/site/docs/advanced/framework.zh-CN.md @@ -41,6 +41,7 @@ EggCore 可以看做是 Koa `Application` 的升级版,默认内置了 [Loader ^ ^ agent worker app worker ``` + ## 如何定制一个框架 你可以直接通过 [egg-boilerplate-framework](https://github.com/eggjs/egg-boilerplate-framework) 脚手架快速上手。 @@ -63,15 +64,18 @@ Egg 框架提供了一些 API,所有继承的框架都需要提供,只增不 Egg 的多进程启动器,通过这个方法来启动 Master,主要的功能实现在 [egg-cluster](https://github.com/eggjs/egg-cluster) 上。因此,直接使用 EggCore 是单进程方式启动的,而 Egg 实现了多进程模式。 ```js -const startCluster = require('egg').startCluster; -startCluster({ +const startCluster = require("egg").startCluster; +startCluster( + { // 应用的代码目录 - baseDir: '/path/to/app', + baseDir: "/path/to/app", // 需要通过这个参数来指定框架目录 - framework: '/path/to/framework', -}, () => { - console.log('app started'); -}); + framework: "/path/to/framework", + }, + () => { + console.log("app started"); + }, +); ``` 所有参数可以查看 [egg-cluster](https://github.com/eggjs/egg-cluster#options)。 @@ -145,26 +149,26 @@ module.exports = Object.assign(egg, { ```js // enterprise -const Application = require('egg').Application; +const Application = require("egg").Application; class EnterpriseApplication extends Application { get [EGG_PATH]() { - return '/path/to/enterprise'; + return "/path/to/enterprise"; } } // 自定义模块的 Application exports.Application = EnterpriseApplication; // department -const EnterpriseApplication = require('enterprise').Application; +const EnterpriseApplication = require("enterprise").Application; // 继承自 enterprise 的 Application class DepartmentApplication extends EnterpriseApplication { get [EGG_PATH]() { - return '/path/to/department'; + return "/path/to/department"; } } // 启动时需要传入 department 的框架路径 -const DepartmentApplication = require('department').Application; +const DepartmentApplication = require("department").Application; const app = new DepartmentApplication(); app.ready(); ``` @@ -178,9 +182,9 @@ app.ready(); ```js // lib/framework.js -const path = require('path'); -const egg = require('egg'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const path = require("path"); +const egg = require("egg"); +const EGG_PATH = Symbol.for("egg#eggPath"); class Application extends egg.Application { get [EGG_PATH]() { @@ -212,9 +216,9 @@ Loader 是应用启动的核心。利用它,我们不仅能规范应用代码 ```js // lib/framework.js -const path = require('path'); -const egg = require('egg'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const path = require("path"); +const egg = require("egg"); +const EGG_PATH = Symbol.for("egg#eggPath"); class YadanAppWorkerLoader extends egg.AppWorkerLoader { load() { @@ -259,6 +263,7 @@ AgentWorkerLoader 的扩展也类似,这里不再赘述。AgentWorkerLoader - 单个 App Worker 通过 framework 找到框架目录,实例化该框架的 Application 类。 - Application 根据 AppWorkerLoader 开始加载,加载顺序类似,会异步等待完成后通知 Master 启动完成。 4. Master 在等到所有 App Worker 发来的启动成功消息后,完成启动,开始对外提供服务。 + ## 框架测试 在看下文之前,请先查看[单元测试章节](../core/unittest.md)。框架测试的大部分使用场景和应用类似。 @@ -268,15 +273,15 @@ AgentWorkerLoader 的扩展也类似,这里不再赘述。AgentWorkerLoader 框架的初始化方式有一定差异。 ```js -const mock = require('egg-mock'); -describe('test/index.test.js', () => { +const mock = require("egg-mock"); +describe("test/index.test.js", () => { let app; before(() => { app = mock.app({ // 转换成 test/fixtures/apps/example - baseDir: 'apps/example', + baseDir: "apps/example", // 重要:配置 framework - framework: true + framework: true, }); return app.ready(); }); @@ -284,8 +289,8 @@ describe('test/index.test.js', () => { after(() => app.close()); afterEach(mock.restore); - it('should success', () => { - return app.httpRequest().get('/').expect(200); + it("should success", () => { + return app.httpRequest().get("/").expect(200); }); }); ``` @@ -301,26 +306,26 @@ describe('test/index.test.js', () => { 在测试多环境场景需要使用到 cache 参数,因为 `mock.app` 默认有缓存,当第一次加载后再次加载会直接读取缓存,那么设置的环境也不会生效。 ```js -const mock = require('egg-mock'); -describe('/test/index.test.js', () => { +const mock = require("egg-mock"); +describe("/test/index.test.js", () => { let app; afterEach(() => app.close()); - it('should test on local', () => { - mock.env('local'); + it("should test on local", () => { + mock.env("local"); app = mock.app({ - baseDir: 'apps/example', + baseDir: "apps/example", framework: true, - cache: false + cache: false, }); return app.ready(); }); - it('should test on prod', () => { - mock.env('prod'); + it("should test on prod", () => { + mock.env("prod"); app = mock.app({ - baseDir: 'apps/example', + baseDir: "apps/example", framework: true, - cache: false + cache: false, }); return app.ready(); }); @@ -334,20 +339,20 @@ describe('/test/index.test.js', () => { 多进程测试和 `mock.app` 参数一致,但 app 的 API 完全不同。不过,SuperTest 依然可用。 ```js -const mock = require('egg-mock'); -describe('/test/index.test.js', () => { +const mock = require("egg-mock"); +describe("/test/index.test.js", () => { let app; before(() => { app = mock.cluster({ - baseDir: 'apps/example', - framework: true + baseDir: "apps/example", + framework: true, }); return app.ready(); }); after(() => app.close()); afterEach(mock.restore); - it('should success', () => { - return app.httpRequest().get('/').expect(200); + it("should success", () => { + return app.httpRequest().get("/").expect(200); }); }); ``` @@ -355,20 +360,20 @@ describe('/test/index.test.js', () => { 多进程测试还可以测试 stdout/stderr,因为 `mock.cluster` 是基于 [coffee](https://github.com/popomore/coffee) 扩展的,可进行进程测试。 ```js -const mock = require('egg-mock'); -describe('/test/index.test.js', () => { +const mock = require("egg-mock"); +describe("/test/index.test.js", () => { let app; before(() => { app = mock.cluster({ - baseDir: 'apps/example', - framework: true + baseDir: "apps/example", + framework: true, }); return app.ready(); }); after(() => app.close()); - it('should get `started`', () => { + it("should get `started`", () => { // 判断终端输出 - app.expect('stdout', /started/); + app.expect("stdout", /started/); }); }); ``` diff --git a/site/docs/advanced/loader-update.zh-CN.md b/site/docs/advanced/loader-update.zh-CN.md index e933ee7757..56f91d2249 100644 --- a/site/docs/advanced/loader-update.zh-CN.md +++ b/site/docs/advanced/loader-update.zh-CN.md @@ -41,7 +41,6 @@ class AppBootHook { module.exports = AppBootHook; ``` - ## ready 函数替代 同样地,我们之前在 `app.ready` 中处理我们的逻辑: @@ -71,7 +70,6 @@ class AppBootHook { module.exports = AppBootHook; ``` - ## beforeClose 函数替代 原先的 `app.beforeClose` 如以下形式: diff --git a/site/docs/advanced/loader.md b/site/docs/advanced/loader.md index 8836cfc009..7f71b146d9 100644 --- a/site/docs/advanced/loader.md +++ b/site/docs/advanced/loader.md @@ -123,16 +123,16 @@ However, there are still some differences: | File | Application | Framework | Plugin | | ---------------------- | ----------- | --------- | ------ | -| app/router.js | ✔︎ | | -| app/controller | ✔︎ | | -| app/middleware | ✔︎ | ✔︎ | ✔︎ | -| app/service | ✔︎ | ✔︎ | ✔︎ | -| app/extend | ✔︎ | ✔︎ | ✔︎ | -| app.js | ✔︎ | ✔︎ | ✔︎ | -| agent.js | ✔︎ | ✔︎ | ✔︎ | -| config/config.{env}.js | ✔︎ | ✔︎ | ✔︎ | -| config/plugin.js | ✔︎ | ✔︎ | -| package.json | ✔︎ | ✔︎ | ✔︎ | +| app/router.js | ✔︎ | | +| app/controller | ✔︎ | | +| app/middleware | ✔︎ | ✔︎ | ✔︎ | +| app/service | ✔︎ | ✔︎ | ✔︎ | +| app/extend | ✔︎ | ✔︎ | ✔︎ | +| app.js | ✔︎ | ✔︎ | ✔︎ | +| agent.js | ✔︎ | ✔︎ | ✔︎ | +| config/config.{env}.js | ✔︎ | ✔︎ | ✔︎ | +| config/plugin.js | ✔︎ | ✔︎ | +| package.json | ✔︎ | ✔︎ | ✔︎ | During the loading process, Egg will traverse all loadUnits to load the files above(application, framework and plugin are different), the loading process has priority. @@ -303,9 +303,9 @@ Egg implements [AppWorkerLoader] and [AgentWorkerLoader] based on the Loader, in ```js // custom AppWorkerLoader // lib/framework.js -const path = require('path'); -const egg = require('egg'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const path = require("path"); +const egg = require("egg"); +const EGG_PATH = Symbol.for("egg#eggPath"); class YadanAppWorkerLoader extends egg.AppWorkerLoader { constructor(opt) { @@ -362,9 +362,9 @@ module.exports = (app) => { // app.js // app/xx.js, as an example, we could load this file in app.js -const path = require('path'); +const path = require("path"); module.exports = (app) => { - app.loader.loadFile(path.join(app.config.baseDir, 'app/xx.js')); + app.loader.loadFile(path.join(app.config.baseDir, "app/xx.js")); }; ``` @@ -378,8 +378,8 @@ Used to load files from a directory into the app, such as `app/controller/home.j // app.js // The following is just an example, using loadController to load controller in practice module.exports = (app) => { - const directory = path.join(app.config.baseDir, 'app/controller'); - app.loader.loadToApp(directory, 'controller'); + const directory = path.join(app.config.baseDir, "app/controller"); + app.loader.loadToApp(directory, "controller"); }; ``` @@ -398,22 +398,20 @@ We load service in this mode as an example: ```js // The following is just an example, using loadService in practice // app/service/user.js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service {} module.exports = UserService; // app.js // get all loadUnit -const servicePaths = app.loader - .getLoadUnits() - .map((unit) => path.join(unit.path, 'app/service')); +const servicePaths = app.loader.getLoadUnits().map((unit) => path.join(unit.path, "app/service")); -app.loader.loadToContext(servicePaths, 'service', { +app.loader.loadToContext(servicePaths, "service", { // service needs to inherit app.Service, so needs app as parameter // enable call will return UserService when loading call: true, // loading file into app.serviceClasses - fieldClass: 'serviceClasses', + fieldClass: "serviceClasses", }); ``` @@ -427,9 +425,9 @@ So this class will only be instantiated when first calling, and will be cached a `ignore` could ignore some files, supports glob, the default is empty. ```js -app.loader.loadToApp(directory, 'controller', { +app.loader.loadToApp(directory, "controller", { // ignore files in app/controller/util - ignore: 'util/**', + ignore: "util/**", }); ``` @@ -444,8 +442,8 @@ module.exports = class User { }; // Loading from app/model, could do some initializations when loading. -const directory = path.join(app.config.baseDir, 'app/model'); -app.loader.loadToApp(directory, 'model', { +const directory = path.join(app.config.baseDir, "app/model"); +app.loader.loadToApp(directory, "model", { initializer(model, opt) { // The first parameter is export's object // The second parameter is an object that only contains current file path. @@ -507,8 +505,8 @@ When you define a loader with `loadToApp` ```js // app.js module.exports = (app) => { - const directory = path.join(app.config.baseDir, 'app/adapter'); - app.loader.loadToApp(directory, 'adapter'); + const directory = path.join(app.config.baseDir, "app/adapter"); + app.loader.loadToApp(directory, "adapter"); }; ``` @@ -521,18 +519,19 @@ module.exports = { // the property name when load to application, E.X. app.adapter adapter: { // relative to app.config.baseDir - directory: 'app/adapter', + directory: "app/adapter", // if inject is ctx, it will use loadToContext - inject: 'app', + inject: "app", // whether load the directory of the framework and plugin loadunit: false, // you can also use other LoaderOptions - } + }, }, }; ``` + ## Reference Links + - [Loader](https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js) - [AppWorkerLoader](https://github.com/eggjs/egg/blob/master/lib/loader/app_worker_loader.js) - [AgentWorkerLoader](https://github.com/eggjs/egg/blob/master/lib/loader/agent_worker_loader.js) - diff --git a/site/docs/advanced/loader.zh-CN.md b/site/docs/advanced/loader.zh-CN.md index 074a23a284..066b390d8e 100644 --- a/site/docs/advanced/loader.zh-CN.md +++ b/site/docs/advanced/loader.zh-CN.md @@ -90,6 +90,7 @@ module.exports = { | Koa | +-----------------------------------+--------+ ``` + ## 加载单元(loadUnit) Egg 将应用、框架和插件都称为加载单元(loadUnit),因为在代码结构上几乎没有什么差异。下面是一种典型的目录结构: @@ -188,6 +189,7 @@ plugin1 是 framework1 依赖的插件。由于 plugin2 和 plugin3 的依赖关 - 加载时如果遇到同名文件将会被覆盖。比如,如果想要覆盖 `ctx.ip`,可以在应用的 `app/extend/context.js` 中直接定义 `ip`。 - 应用完整启动顺序请查看[框架开发](./framework.md)。 + ### 生命周期 框架提供了以下生命周期函数供开发者使用: @@ -282,6 +284,7 @@ module.exports = AppBootHook; - `app/service/userInfo.js` => `app.service.userInfo` Loader 也提供了 [caseStyle](#caseStyle-string) 设置来强制指定命名方式,如将 model 加载时的 API 首字母大写,`app/model/user.js` => `app.model.User`,可指定 `caseStyle: 'upper'`。 + ## 扩展 Loader `Loader` 是一个基类,并根据文件加载的规则提供了一些内置的方法。它本身并不会去调用这些方法,而是由继承类调用。 @@ -306,9 +309,9 @@ Loader 也提供了 [caseStyle](#caseStyle-string) 设置来强制指定命名 ```js // 自定义 AppWorkerLoader // lib/framework.js -const path = require('path'); -const egg = require('egg'); -const EGG_PATH = Symbol.for('egg#eggPath'); +const path = require("path"); +const egg = require("egg"); +const EGG_PATH = Symbol.for("egg#eggPath"); class YadanAppWorkerLoader extends egg.AppWorkerLoader { constructor(opt) { @@ -348,6 +351,7 @@ module.exports = Object.assign(egg, { 通过 `Loader` 提供的这些 API,可以很方便地定制团队的自定义加载,例如 `this.model.xx`,`app/extend/filter.js` 等等。 以上只是说明 `Loader` 的写法,具体可以查看[框架开发](./framework.md)。 + ## 加载器函数(Loader API) Loader 提供了一些基础 API,方便在扩展时简化代码。想了解所有相关 API,请[点击此处](https://github.com/eggjs/egg-core#eggloader)。 @@ -364,9 +368,9 @@ module.exports = (app) => { // app.js // 以 app/xx.js 为例子,在 app.js 中加载此文件: -const path = require('path'); +const path = require("path"); module.exports = (app) => { - app.loader.loadFile(path.join(app.config.baseDir, 'app/xx.js')); + app.loader.loadFile(path.join(app.config.baseDir, "app/xx.js")); }; ``` @@ -380,8 +384,8 @@ module.exports = (app) => { // app.js // 以下只是示例,加载 controller 请用 loadController module.exports = (app) => { - const directory = path.join(app.config.baseDir, 'app/controller'); - app.loader.loadToApp(directory, 'controller'); + const directory = path.join(app.config.baseDir, "app/controller"); + app.loader.loadToApp(directory, "controller"); }; ``` @@ -400,26 +404,25 @@ module.exports = (app) => { ```js // 以下为示例,请使用 loadService // app/service/user.js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service {} module.exports = UserService; // app.js // 获取所有的 loadUnit -const servicePaths = app.loader - .getLoadUnits() - .map((unit) => path.join(unit.path, 'app/service')); +const servicePaths = app.loader.getLoadUnits().map((unit) => path.join(unit.path, "app/service")); -app.loader.loadToContext(servicePaths, 'service', { +app.loader.loadToContext(servicePaths, "service", { // service 需要继承 app.Service,因此需要 app 参数 // 设置 call 为 true,会在加载时调用函数,并返回 UserService call: true, // 将文件加载到 app.serviceClasses - fieldClass: 'serviceClasses', + fieldClass: "serviceClasses", }); ``` 文件加载完成后,`app.serviceClasses.user` 就代表 UserService 类。当调用 `ctx.service.user` 时,会实例化 UserService 类。因此,这个类只有在每次请求中首次被访问时才会实例化。实例化后,对象会被缓存,同一个请求中多次调用也只实例化一次。 + ### LoaderOptions #### ignore [String] @@ -427,9 +430,9 @@ app.loader.loadToContext(servicePaths, 'service', { `ignore` 可用于忽略某些文件,支持 glob 匹配模式,默认值为空。 ```js -app.loader.loadToApp(directory, 'controller', { +app.loader.loadToApp(directory, "controller", { // 忽略 app/controller/util 目录下的文件 - ignore: 'util/**', + ignore: "util/**", }); ``` @@ -444,8 +447,8 @@ module.exports = class User { }; // 从 app/model 目录加载,且可以在加载时进行一些初始化处理 -const directory = path.join(app.config.baseDir, 'app/model'); -app.loader.loadToApp(directory, 'model', { +const directory = path.join(app.config.baseDir, "app/model"); +app.loader.loadToApp(directory, "model", { initializer(model, opt) { // 第一个参数为 export 的对象 // 第二个参数为一个对象,里面包含当前文件的路径 @@ -459,6 +462,7 @@ app.loader.loadToApp(directory, 'model', { 设置文件命名的转换规则,可选项为 `camel`、`upper` 或 `lower`,默认值为 `camel`。 这些选项都会将文件名转换为驼峰命名,但是首字符的大小写处理不同: + - `camel`:首字母保持不变。 - `upper`:首字母转为大写。 - `lower`:首字母转为小写。 @@ -466,23 +470,24 @@ app.loader.loadToApp(directory, 'model', { 根据不同文件类型设置相应的转换规则,如下表所示: | 文件类型 | `caseStyle` 配置 | -| ------------- | -------------- | -| app/controller | lower | -| app/middleware | lower | -| app/service | lower | +| -------------- | ---------------- | +| app/controller | lower | +| app/middleware | lower | +| app/service | lower | #### override [Boolean] 当存在同名文件时,是否覆盖原有文件,或抛出异常。默认值为 `false`。 例如,当同时加载应用和插件中的 `app/service/user.js` 文件时: + - 若 `override` 设为 `true`,则应用中的文件会覆盖插件中的同名文件。 - 若设为 `false`,则在尝试加载应用中的文件时会报错。 根据不同文件类型设置 `override` 的配置值,如下表所示: | 文件类型 | `override` 配置 | -| ------------- | --------------- | +| -------------- | --------------- | | app/controller | true | | app/middleware | false | | app/service | false | @@ -493,12 +498,11 @@ app.loader.loadToApp(directory, 'model', { 根据不同文件类型设置 `call` 的配置值,如下表所示: -| 文件类型 | `call` 配置 | -| ------------- | ------------- | -| app/controller | true | -| app/middleware | false | -| app/service | true | - +| 文件类型 | `call` 配置 | +| -------------- | ----------- | +| app/controller | true | +| app/middleware | false | +| app/service | true | ## CustomLoader @@ -509,8 +513,8 @@ app.loader.loadToApp(directory, 'model', { ```js // app.js module.exports = (app) => { - const directory = path.join(app.config.baseDir, 'app/adapter'); - app.loader.loadToApp(directory, 'adapter'); + const directory = path.join(app.config.baseDir, "app/adapter"); + app.loader.loadToApp(directory, "adapter"); }; ``` @@ -523,9 +527,9 @@ module.exports = { // 在 app 对象上定义的属性名为 app.adapter adapter: { // 路径相对于 app.config.baseDir - directory: 'app/adapter', + directory: "app/adapter", // 如果用于 ctx,则应该使用 loadToContext 方法 - inject: 'app', + inject: "app", // 是否加载框架和插件的目录 loadunit: false, // 也可以定义其他 LoaderOptions @@ -535,6 +539,7 @@ module.exports = { ``` 参考链接: + - [loader](https://github.com/eggjs/egg-core/blob/master/lib/loader/egg_loader.js) - [appworkerloader](https://github.com/eggjs/egg/blob/master/lib/loader/app_worker_loader.js) -- [agentworkerloader](https://github.com/eggjs/egg/blob/master/lib/loader/agent_worker_loader.js) \ No newline at end of file +- [agentworkerloader](https://github.com/eggjs/egg/blob/master/lib/loader/agent_worker_loader.js) diff --git a/site/docs/advanced/plugin.md b/site/docs/advanced/plugin.md index f661568924..c81b42091d 100644 --- a/site/docs/advanced/plugin.md +++ b/site/docs/advanced/plugin.md @@ -60,13 +60,11 @@ Plugin is actually a `mini application`, directory of plugin is as below: It is almost the same as the application directory, what're the differences? 1. Plugin have no independant router or controller. This is because: - - Usually routers are strongly bound to application, it is not fit here. - An application might have plenty of dependant plugins, routers of plugin are very possible conflict with others. It would be a disaster. - If you really need a general router, you should implement it as middleware of the plugin. 2. The specific information of plugin should be declared in the `package.json` of `eggPlugin`: - - `{String} name` - plugin name(required), it must be unique, it will be used in the config of the dependencies of plugins. - `{Array} dependencies` - strong dependent plugins list of the current plugin(if one of these plugins here is not found, application's startup will fail). - `{Array} optionalDependencies` - optional dependencies list of this plugin.(if these plugins are not activated, only warnings would be occurred, and will not affect the startup of the application). @@ -85,7 +83,6 @@ It is almost the same as the application directory, what're the differences? ``` 3. No `plugin.js`: - - `eggPlugin.dependencies` is for declaring dependencies only, not for importing, nor activating. - If you want to manage multiple plugins, you should do it in[upper framework](./framework.md) @@ -150,24 +147,24 @@ Extend the built-in objects of the framework, just like the application 1. First, define and implement middleware under directory `app/middleware`: ```js - 'use strict'; + "use strict"; - const staticCache = require('koa-static-cache'); - const assert = require('assert'); - const mkdirp = require('mkdirp'); + const staticCache = require("koa-static-cache"); + const assert = require("assert"); + const mkdirp = require("mkdirp"); module.exports = (options, app) => { assert.strictEqual( typeof options.dir, - 'string', - 'Must set `app.config.static.dir` when static plugin enable', + "string", + "Must set `app.config.static.dir` when static plugin enable", ); // ensure directory exists mkdirp.sync(options.dir); app.loggers.coreLogger.info( - '[egg-static] starting static serve %s -> %s', + "[egg-static] starting static serve %s -> %s", options.prefix, options.dir, ); @@ -179,14 +176,14 @@ Extend the built-in objects of the framework, just like the application 2. Insert middleware to the appropriate position in `app.js`(e.g. insert static middleware before bodyParser): ```js - const assert = require('assert'); + const assert = require("assert"); module.exports = (app) => { // insert static middleware before bodyParser - const index = app.config.coreMiddleware.indexOf('bodyParser'); - assert(index >= 0, 'bodyParser highly needed'); + const index = app.config.coreMiddleware.indexOf("bodyParser"); + assert(index >= 0, "bodyParser highly needed"); - app.config.coreMiddleware.splice(index, 0, 'static'); + app.config.coreMiddleware.splice(index, 0, "static"); }; ``` @@ -196,13 +193,13 @@ Extend the built-in objects of the framework, just like the application ```js // ${plugin_root}/app.js - const fs = require('fs'); - const path = require('path'); + const fs = require("fs"); + const path = require("path"); module.exports = (app) => { - app.customData = fs.readFileSync(path.join(app.config.baseDir, 'data.bin')); + app.customData = fs.readFileSync(path.join(app.config.baseDir, "data.bin")); - app.coreLogger.info('read data ok'); + app.coreLogger.info("read data ok"); }; ``` @@ -210,16 +207,16 @@ Extend the built-in objects of the framework, just like the application ```js // ${plugin_root}/app.js - const MyClient = require('my-client'); + const MyClient = require("my-client"); module.exports = (app) => { app.myClient = new MyClient(); - app.myClient.on('error', (err) => { + app.myClient.on("error", (err) => { app.coreLogger.error(err); }); app.beforeStart(async () => { await app.myClient.ready(); - app.coreLogger.info('my client is ready'); + app.coreLogger.info("my client is ready"); }); }; ``` @@ -228,16 +225,16 @@ Extend the built-in objects of the framework, just like the application ```js // ${plugin_root}/agent.js - const MyClient = require('my-client'); + const MyClient = require("my-client"); module.exports = (agent) => { agent.myClient = new MyClient(); - agent.myClient.on('error', (err) => { + agent.myClient.on("error", (err) => { agent.coreLogger.error(err); }); agent.beforeStart(async () => { await agent.myClient.ready(); - agent.coreLogger.info('my client is ready'); + agent.coreLogger.info("my client is ready"); }); }; ``` @@ -260,8 +257,8 @@ Extend the built-in objects of the framework, just like the application ```js exports.schedule = { - type: 'worker', - cron: '0 0 3 * * *', + type: "worker", + cron: "0 0 3 * * *", // interval: '1h', // immediate: true, }; @@ -289,7 +286,7 @@ We simplify the [egg-mysql] plugin to see how to write it: module.exports = (app) => { // The first parameter mysql defines the field mounted to app, we can access MySQL singleton instance via `app.mysql` // The second parameter createMysql accepts two parameters (config, app), and then returns a MySQL instance - app.addSingleton('mysql', createMysql); + app.addSingleton("mysql", createMysql); }; /** @@ -304,7 +301,7 @@ function createMysql(config, app) { // check before start the application app.beforeStart(async () => { - const rows = await client.query('select now() as currentTime;'); + const rows = await client.query("select now() as currentTime;"); app.coreLogger.info( `[egg-mysql] init instance success, rds currentTime: ${rows[0].currentTime}`, ); @@ -320,20 +317,13 @@ The initialization function also supports `Async function`, convenient for some async function createMysql(config, app) { // get mysql configurations asynchronous const mysqlConfig = await app.configManager.getMysqlConfig(config.mysql); - assert( - mysqlConfig.host && - mysqlConfig.port && - mysqlConfig.user && - mysqlConfig.database, - ); + assert(mysqlConfig.host && mysqlConfig.port && mysqlConfig.user && mysqlConfig.database); // create instance const client = new Mysql(mysqlConfig); // check before start the application - const rows = await client.query('select now() as currentTime;'); - app.coreLogger.info( - `[egg-mysql] init instance success, rds currentTime: ${rows[0].currentTime}`, - ); + const rows = await client.query("select now() as currentTime;"); + app.coreLogger.info(`[egg-mysql] init instance success, rds currentTime: ${rows[0].currentTime}`); return client; } @@ -352,11 +342,11 @@ As you can see, all we need to do for this plugin is passing the fields that nee module.exports = { mysql: { client: { - host: 'mysql.com', - port: '3306', - user: 'test_user', - password: 'test_password', - database: 'test', + host: "mysql.com", + port: "3306", + user: "test_user", + password: "test_password", + database: "test", }, }, }; @@ -383,20 +373,20 @@ As you can see, all we need to do for this plugin is passing the fields that nee clients: { // clientId, access the client instance by app.mysql.get('clientId') db1: { - user: 'user1', - password: 'upassword1', - database: 'db1', + user: "user1", + password: "upassword1", + database: "db1", }, db2: { - user: 'user2', - password: 'upassword2', - database: 'db2', + user: "user2", + password: "upassword2", + database: "db2", }, }, // default configuration for all databases default: { - host: 'mysql.com', - port: '3306', + host: "mysql.com", + port: "3306", }, }; ``` @@ -421,7 +411,7 @@ Instead of declaring the configuration in the configuration file in advance, we module.exports = (app) => { app.beforeStart(async () => { // get MySQL config from configuration center { host, post, password, ... } - const mysqlConfig = await app.configCenter.fetch('mysql'); + const mysqlConfig = await app.configCenter.fetch("mysql"); // create MySQL instance dynamically app.database = app.mysql.createInstanceAsync(mysqlConfig); }); @@ -447,7 +437,6 @@ When loading the plugins in the framework, it will follow the rules below: - If there is the path configuration, load them in path directly. - If there is no path configuration, search them with the package name, the search orders are: - 1. `node_modules` directory of the application root 2. `node_modules` directory of the dependencies 3. `node_modules` of current directory(generally for unit test compatibility) @@ -461,7 +450,6 @@ It's well welcomed to your contributions to the new plugins, but also hope you f - The corresponding plugin should be named in camel-case. The name should be translated according to the middle-lines of the `npm` name:`egg-foo-bar` => `fooBar`. - The use of middle-lines is not compulsive, e.g: userservice(egg-userservice) and user-service(egg-user-service) are both acceptable. - `package.json` Rules: - - Add `eggPlugin` property according to the details discussed before. - For convenient index, add `egg`,`egg-plugin`,`eggPlugin` in `keywords`: @@ -474,14 +462,7 @@ It's well welcomed to your contributions to the new plugins, but also hope you f "name": "nunjucks", "dep": ["security"] }, - "keywords": [ - "egg", - "egg-plugin", - "eggPlugin", - "egg-plugin-view", - "egg-view", - "nunjucks" - ] + "keywords": ["egg", "egg-plugin", "eggPlugin", "egg-plugin-view", "egg-view", "nunjucks"] } ``` diff --git a/site/docs/advanced/plugin.zh-CN.md b/site/docs/advanced/plugin.zh-CN.md index 3372cf9775..cb0ce7d6a0 100644 --- a/site/docs/advanced/plugin.zh-CN.md +++ b/site/docs/advanced/plugin.zh-CN.md @@ -59,13 +59,11 @@ $ npm test 那区别在哪儿呢? 1. 插件没有独立的 router 和 controller。这主要出于几点考虑: - - 路由一般和应用强绑定的,不具备通用性。 - 一个应用可能依赖很多个插件,如果插件支持路由可能会导致路由冲突。 - 如果确实有统一路由的需求,可以考虑在插件里通过中间件来实现。 2. 插件需要在 `package.json` 中的 `eggPlugin` 节点指定插件特有的信息: - - `{String} name` - 插件名(必须配置),具有唯一性,配置依赖关系时会指定依赖插件的 name。 - `{Array} dependencies` - 当前插件强依赖的插件列表(如果依赖的插件没找到,应用启动失败)。 - `{Array} optionalDependencies` - 当前插件的可选依赖插件列表(如果依赖的插件未开启,只会 warning,不会影响应用启动)。 @@ -84,7 +82,6 @@ $ npm test ``` 3. 插件没有 `plugin.js`: - - `eggPlugin.dependencies` 只是用于声明依赖关系,而不是引入插件或开启插件。 - 如果期望统一管理多个插件的开启和配置,可以在 [上层框架](./framework.md) 处理。 @@ -128,6 +125,7 @@ $ npm test - 弱依赖,比如:A 依赖 B,但是如果没有 B,A 有相应的降级方案。 需要特别强调的是:如果采用 `optionalDependencies`,那么框架不会校验依赖的插件是否开启,它的作用仅仅是计算加载顺序。所以,这时候依赖方需要通过“接口探测”等方式来决定相应的处理逻辑。 + ## 插件能做什么? 上面给出了插件的定义,那插件到底能做什么? @@ -148,24 +146,24 @@ $ npm test 1. 首先在 `app/middleware` 目录下定义好中间件实现: ```js - 'use strict'; + "use strict"; - const staticCache = require('koa-static-cache'); - const assert = require('assert'); - const mkdirp = require('mkdirp'); + const staticCache = require("koa-static-cache"); + const assert = require("assert"); + const mkdirp = require("mkdirp"); module.exports = (options, app) => { assert.strictEqual( typeof options.dir, - 'string', - 'Must set `app.config.static.dir` when static plugin enable', + "string", + "Must set `app.config.static.dir` when static plugin enable", ); // 确保目录存在 mkdirp.sync(options.dir); app.loggers.coreLogger.info( - '[egg-static] starting static serve %s -> %s', + "[egg-static] starting static serve %s -> %s", options.prefix, options.dir, ); @@ -177,14 +175,14 @@ $ npm test 2. 在 `app.js` 中将中间件插入到合适的位置(例如:下面将 static 中间件放到 bodyParser 之前): ```js - const assert = require('assert'); + const assert = require("assert"); module.exports = (app) => { // 将 static 中间件放到 bodyParser 之前 - const index = app.config.coreMiddleware.indexOf('bodyParser'); - assert(index >= 0, 'bodyParser 中间件必须存在'); + const index = app.config.coreMiddleware.indexOf("bodyParser"); + assert(index >= 0, "bodyParser 中间件必须存在"); - app.config.coreMiddleware.splice(index, 0, 'static'); + app.config.coreMiddleware.splice(index, 0, "static"); }; ``` @@ -194,13 +192,13 @@ $ npm test ```js // ${plugin_root}/app.js - const fs = require('fs'); - const path = require('path'); + const fs = require("fs"); + const path = require("path"); module.exports = (app) => { - app.customData = fs.readFileSync(path.join(app.config.baseDir, 'data.bin')); + app.customData = fs.readFileSync(path.join(app.config.baseDir, "data.bin")); - app.coreLogger.info('Data read successfully'); + app.coreLogger.info("Data read successfully"); }; ``` @@ -208,16 +206,16 @@ $ npm test ```js // ${plugin_root}/app.js - const MyClient = require('my-client'); + const MyClient = require("my-client"); module.exports = (app) => { app.myClient = new MyClient(); - app.myClient.on('error', (err) => { + app.myClient.on("error", (err) => { app.coreLogger.error(err); }); app.beforeStart(async () => { await app.myClient.ready(); - app.coreLogger.info('My client is ready'); + app.coreLogger.info("My client is ready"); }); }; ``` @@ -226,19 +224,20 @@ $ npm test ```js // ${plugin_root}/agent.js - const MyClient = require('my-client'); + const MyClient = require("my-client"); module.exports = (agent) => { agent.myClient = new MyClient(); - agent.myClient.on('error', (err) => { + agent.myClient.on("error", (err) => { agent.coreLogger.error(err); }); agent.beforeStart(async () => { await agent.myClient.ready(); - agent.coreLogger.info('My client is ready'); + agent.coreLogger.info("My client is ready"); }); }; ``` + ### 设置定时任务 1. 在 `package.json` 里设置依赖 schedule 插件 @@ -257,8 +256,8 @@ $ npm test ```js exports.schedule = { - type: 'worker', - cron: '0 0 3 * * *', + type: "worker", + cron: "0 0 3 * * *", // interval: '1h', // immediate: true }; @@ -283,8 +282,8 @@ $ npm test ```js // egg-mysql/app.js -module.exports = app => { - app.addSingleton('mysql', createMysql); +module.exports = (app) => { + app.addSingleton("mysql", createMysql); }; /** @@ -299,8 +298,10 @@ function createMysql(config, app) { // 应用启动前检查 app.beforeStart(async () => { - const rows = await client.query('select now() as currentTime;'); - app.coreLogger.info(`[egg-mysql] init instance success, rds currentTime: ${rows[0].currentTime}`); + const rows = await client.query("select now() as currentTime;"); + app.coreLogger.info( + `[egg-mysql] init instance success, rds currentTime: ${rows[0].currentTime}`, + ); }); return client; @@ -318,7 +319,7 @@ async function createMysql(config, app) { const client = new Mysql(mysqlConfig); // 应用启动前检查 - const rows = await client.query('select now() as currentTime;'); + const rows = await client.query("select now() as currentTime;"); app.coreLogger.info(`[egg-mysql] init instance success, rds currentTime: ${rows[0].currentTime}`); return client; @@ -326,6 +327,7 @@ async function createMysql(config, app) { ``` 可以看到,插件中我们只需要提供要挂载的字段和服务的初始化方法,所有配置管理、实例获取方式由框架封装并统一提供。 + #### 应用层使用方案 ##### 单实例 @@ -337,11 +339,11 @@ async function createMysql(config, app) { module.exports = { mysql: { client: { - host: 'mysql.com', - port: '3306', - user: 'test_user', - password: 'test_password', - database: 'test', + host: "mysql.com", + port: "3306", + user: "test_user", + password: "test_password", + database: "test", }, }, }; @@ -368,20 +370,20 @@ async function createMysql(config, app) { clients: { // clientId,可通过 app.mysql.get('clientId') 访问客户端实例 db1: { - user: 'user1', - password: 'upassword1', - database: 'db1', + user: "user1", + password: "upassword1", + database: "db1", }, db2: { - user: 'user2', - password: 'upassword2', - database: 'db2', + user: "user2", + password: "upassword2", + database: "db2", }, }, // 所有数据库的默认配置 default: { - host: 'mysql.com', - port: '3306', + host: "mysql.com", + port: "3306", }, }; ``` @@ -392,7 +394,7 @@ async function createMysql(config, app) { // app/controller/post.js class PostController extends Controller { async list() { - const posts = await this.app.mysql.get('db1').query(sql, values); + const posts = await this.app.mysql.get("db1").query(sql, values); } } ``` @@ -403,10 +405,10 @@ async function createMysql(config, app) { ```js // app.js -module.exports = app => { +module.exports = (app) => { app.beforeStart(async () => { // 从配置中心获取 MySQL 配置 { host, port, password, ... } - const mysqlConfig = await app.configCenter.fetch('mysql'); + const mysqlConfig = await app.configCenter.fetch("mysql"); // 动态创建 MySQL 实例 app.database = await app.mysql.createInstanceAsync(mysqlConfig); }); @@ -435,6 +437,7 @@ class PostController extends Controller { 1. 应用根目录下的 `node_modules` 2. 应用依赖框架路径下的 `node_modules` 3. 当前路径下的 `node_modules`(主要是兼容单元测试场景) + ### 插件规范 我们非常欢迎你贡献新的插件,同时也希望你遵守下面一些规范: @@ -445,7 +448,6 @@ class PostController extends Controller { - 对于既可以加中划线也可以不加的情况,不做强制约定,例如:`userservice`(`egg-userservice`)或 `user-service`(`egg-user-service`)都可。 - `package.json` 书写规范 - - 按照上面的文档添加 `eggPlugin` 节点。 - 在 `keywords` 里添加 `egg`、`egg-plugin`、`eggPlugin` 等关键字,便于索引。 @@ -458,14 +460,7 @@ class PostController extends Controller { "name": "nunjucks", "dep": ["security"] }, - "keywords": [ - "egg", - "egg-plugin", - "eggPlugin", - "egg-plugin-view", - "egg-view", - "nunjucks" - ] + "keywords": ["egg", "egg-plugin", "eggPlugin", "egg-plugin-view", "egg-view", "nunjucks"] } ``` @@ -479,7 +474,6 @@ Egg 通过 `eggPlugin.name` 来定义插件名,只需应用或框架具备唯 **将相同功能的插件赋予相同的插件名,以及提供相同的 API,可以快速进行切换**。这种做法在模板、数据库等领域非常适用。 - [egg-boilerplate-plugin]: https://github.com/eggjs/egg-boilerplate-plugin [egg-mysql]: https://github.com/eggjs/egg-mysql [egg-oss]: https://github.com/eggjs/egg-oss diff --git a/site/docs/advanced/view-plugin.md b/site/docs/advanced/view-plugin.md index af52222dab..e130695ec0 100644 --- a/site/docs/advanced/view-plugin.md +++ b/site/docs/advanced/view-plugin.md @@ -57,11 +57,10 @@ The base class of the View needs to provide `render` and `renderString` methods The following is a simplified code that can be directly [view source](https://github.com/eggjs/egg-view-ejs/blob/master/lib/view.js) ```js -const ejs = require('ejs'); +const ejs = require("ejs"); Mmdule.exports = class EjsView { render(filename, locals, viewOptions) { - const config = Object.assign({}, this.config, viewOptions, { filename }); return new Promise((resolve, reject) => { @@ -150,7 +149,7 @@ module.exports = (app) => { ```js // {plugin_root}/lib/view.js -const ViewHelper = require('./helper'); +const ViewHelper = require("./helper"); module.exports = class MyCustomView { render(filename, locals) { diff --git a/site/docs/advanced/view-plugin.zh-CN.md b/site/docs/advanced/view-plugin.zh-CN.md index e2a1617fe7..7c3ebfa4ad 100644 --- a/site/docs/advanced/view-plugin.zh-CN.md +++ b/site/docs/advanced/view-plugin.zh-CN.md @@ -8,6 +8,7 @@ order: 5 本文将阐述框架对 View 插件的规范约束。我们可以依此来封装对应的模板引擎插件。以下以 [egg-view-ejs](https://github.com/eggjs/egg-view-ejs) 为例。 ## 插件目录结构 + ```bash egg-view-ejs ├── config @@ -54,11 +55,10 @@ View 基类需要提供 `render` 和 `renderString` 两个方法,支持 genera 以下为简化代码,您可以直接[查看源码](https://github.com/eggjs/egg-view-ejs/blob/master/lib/view.js): ```js -const ejs = require('ejs'); +const ejs = require("ejs"); Mmdule.exports = class EjsView { render(filename, locals, viewOptions) { - const config = Object.assign({}, this.config, viewOptions, { filename }); return new Promise((resolve, reject) => { @@ -88,14 +88,16 @@ Mmdule.exports = class EjsView { ### 参数 `render` 方法的参数: - - `filename`:是完整文件路径,框架查找文件时已确认文件是否存在,因此这里不需要处理。 - - `locals`:渲染所需数据,来源包括 `app.locals`、`ctx.locals` 以及调用 `render` 方法传入的数据。框架还内置了 `ctx`、`request` 和 `ctx.helper` 这几个对象。 - - `viewOptions`:用户传入的配置,可以覆盖模板引擎的默认配置。这个可根据模板引擎的特征考虑是否支持。例如,默认开启了缓存,而某个页面不需要缓存。 + +- `filename`:是完整文件路径,框架查找文件时已确认文件是否存在,因此这里不需要处理。 +- `locals`:渲染所需数据,来源包括 `app.locals`、`ctx.locals` 以及调用 `render` 方法传入的数据。框架还内置了 `ctx`、`request` 和 `ctx.helper` 这几个对象。 +- `viewOptions`:用户传入的配置,可以覆盖模板引擎的默认配置。这个可根据模板引擎的特征考虑是否支持。例如,默认开启了缓存,而某个页面不需要缓存。 `renderString` 方法的三个参数: - - `tpl`: 模板字符串,没有文件路径。 - - `locals`: 同 `render`。 - - `viewOptions`: 同 `render`。 + +- `tpl`: 模板字符串,没有文件路径。 +- `locals`: 同 `render`。 +- `viewOptions`: 同 `render`。 ## 插件配置 @@ -107,8 +109,8 @@ Mmdule.exports = class EjsView { // config/config.default.js module.exports = { ejs: { - cache: true - } + cache: true, + }, }; ``` @@ -145,7 +147,7 @@ module.exports = (app) => { ```js // {plugin_root}/lib/view.js -const ViewHelper = require('./helper'); +const ViewHelper = require("./helper"); module.exports = class MyCustomView { render(filename, locals) { diff --git a/site/docs/basics/app-start.md b/site/docs/basics/app-start.md index 7ae4b05c65..3d8207adf2 100644 --- a/site/docs/basics/app-start.md +++ b/site/docs/basics/app-start.md @@ -34,8 +34,8 @@ class AppBootHook { // For example: the password in the parameter is encrypted, decrypt it here this.app.config.mysql.password = decrypt(this.app.config.mysql.password); // For example: insert a middleware into the framework's coreMiddleware - const statusIdx = this.app.config.coreMiddleware.indexOf('status'); - this.app.config.coreMiddleware.splice(statusIdx + 1, 0, 'limit'); + const statusIdx = this.app.config.coreMiddleware.indexOf("status"); + this.app.config.coreMiddleware.splice(statusIdx + 1, 0, "limit"); } async didLoad() { @@ -47,8 +47,8 @@ class AppBootHook { await this.app.queue.init(); // For example: load a custom directory - this.app.loader.loadToContext(path.join(__dirname, 'app/tasks'), 'tasks', { - fieldClass: 'tasksClasses', + this.app.loader.loadToContext(path.join(__dirname, "app/tasks"), "tasks", { + fieldClass: "tasksClasses", }); } @@ -72,7 +72,7 @@ class AppBootHook { // http / https server has started and begins accepting external requests // At this point you can get an instance of server from app.server - this.app.server.on('timeout', (socket) => { + this.app.server.on("timeout", (socket) => { // handle socket timeout }); } diff --git a/site/docs/basics/app-start.zh-CN.md b/site/docs/basics/app-start.zh-CN.md index 34123fb508..b0721c7996 100644 --- a/site/docs/basics/app-start.zh-CN.md +++ b/site/docs/basics/app-start.zh-CN.md @@ -8,6 +8,7 @@ order: 12 框架提供了统一的入口文件(`app.js`)进行启动过程自定义。这个文件需要返回一个 Boot 类。我们可以通过定义 Boot 类中的生命周期方法来执行启动应用过程中的初始化工作。 框架提供了以下 [生命周期函数](../advanced/loader.md#life-cycles) 供开发人员处理: + - 配置文件即将加载,这是最后动态修改配置的时机(`configWillLoad`); - 配置文件加载完成(`configDidLoad`); - 文件加载完成(`didLoad`); @@ -33,8 +34,8 @@ class AppBootHook { // 例如:参数中的密码是加密的,在此处进行解密 this.app.config.mysql.password = decrypt(this.app.config.mysql.password); // 例如:插入一个中间件到框架的 coreMiddleware 之间 - const statusIdx = this.app.config.coreMiddleware.indexOf('status'); - this.app.config.coreMiddleware.splice(statusIdx + 1, 0, 'limit'); + const statusIdx = this.app.config.coreMiddleware.indexOf("status"); + this.app.config.coreMiddleware.splice(statusIdx + 1, 0, "limit"); } async didLoad() { @@ -46,8 +47,8 @@ class AppBootHook { await this.app.queue.init(); // 例如:加载自定义目录 - this.app.loader.loadToContext(path.join(__dirname, 'app/tasks'), 'tasks', { - fieldClass: 'tasksClasses', + this.app.loader.loadToContext(path.join(__dirname, "app/tasks"), "tasks", { + fieldClass: "tasksClasses", }); } @@ -70,7 +71,7 @@ class AppBootHook { // http/https 服务器已启动,开始接收外部请求 // 此时可以从 app.server 获取 server 实例 - this.app.server.on('timeout', socket => { + this.app.server.on("timeout", (socket) => { // 处理 socket 超时 }); } @@ -81,4 +82,4 @@ module.exports = AppBootHook; **注意:在自定义生命周期函数中,不建议进行耗时的操作,因为框架会有启动的超时检测。** -如果你的 Egg 框架的生命周期函数是旧版本的,建议你将其升级到类方法模式;详情请查看[升级你的生命周期事件函数](../advanced/loader-update.md)。 \ No newline at end of file +如果你的 Egg 框架的生命周期函数是旧版本的,建议你将其升级到类方法模式;详情请查看[升级你的生命周期事件函数](../advanced/loader-update.md)。 diff --git a/site/docs/basics/config.md b/site/docs/basics/config.md index 5ff318f8ca..5827367b85 100644 --- a/site/docs/basics/config.md +++ b/site/docs/basics/config.md @@ -37,7 +37,7 @@ The configuration file returns an object which could overwrite some configuratio // configure the catalog of logger,the default configuration of logger is provided by framework module.exports = { logger: { - dir: '/home/admin/logs/demoapp', + dir: "/home/admin/logs/demoapp", }, }; ``` @@ -45,9 +45,9 @@ module.exports = { The configuration file can simplify to `exports.key = value` format ```js -exports.keys = 'my-cookie-secret-key'; +exports.keys = "my-cookie-secret-key"; exports.logger = { - level: 'DEBUG', + level: "DEBUG", }; ``` @@ -55,11 +55,11 @@ The configuration file can also return a function which could receive a paramete ```js // put the catalog of logger to the catalog of codes -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { logger: { - dir: path.join(appInfo.baseDir, 'logs'), + dir: path.join(appInfo.baseDir, "logs"), }, }; }; @@ -81,10 +81,10 @@ Choose the appropriate style according to the specific situation, but please mak ```js // config/config.default.js -exports.someKeys = 'abc'; +exports.someKeys = "abc"; module.exports = (appInfo) => { const config = {}; - config.keys = '123456'; + config.keys = "123456"; return config; }; ``` diff --git a/site/docs/basics/config.zh-CN.md b/site/docs/basics/config.zh-CN.md index 300911e9b3..498e50fceb 100644 --- a/site/docs/basics/config.zh-CN.md +++ b/site/docs/basics/config.zh-CN.md @@ -12,6 +12,7 @@ order: 4 3. 使用代码管理配置,在代码中添加多个环境的配置,在启动时传入当前环境的参数即可。但无法全局配置,必须修改代码。 我们选择了最后一种配置方案,**配置即代码**,配置的变更也应该经过审核后才能发布。应用包本身是可以部署在多个环境的,只需要指定运行环境即可。 + ### 多环境配置 框架支持根据环境来加载配置,定义多个环境的配置文件,具体环境请查看[运行环境配置](./env.md)。 @@ -27,6 +28,7 @@ config `config.default.js` 为默认的配置文件,所有环境都会加载这个配置文件,一般也会作为开发环境的默认配置文件。 当指定 `env` 时,会同时加载默认配置和对应的配置(具名配置)文件。具名配置和默认配置将合并(使用 [extend2](https://www.npmjs.com/package/extend2) 深拷贝)成最终配置,具名配置项会覆盖默认配置文件的同名配置。例如,`prod` 环境会加载 `config.prod.js` 和 `config.default.js` 文件,`config.prod.js` 会覆盖 `config.default.js` 的同名配置。 + ### 配置写法 配置文件返回的是一个对象,可以覆盖框架的一些配置,应用也可以将自己业务的配置放到这里方便管理。 @@ -35,7 +37,7 @@ config // 配置 logger 文件的目录,logger 默认配置由框架提供 module.exports = { logger: { - dir: '/home/admin/logs/demoapp', + dir: "/home/admin/logs/demoapp", }, }; ``` @@ -43,9 +45,9 @@ module.exports = { 配置文件也可以简化地写成 `exports.key = value` 形式: ```js -exports.keys = 'my-cookie-secret-key'; +exports.keys = "my-cookie-secret-key"; exports.logger = { - level: 'DEBUG', + level: "DEBUG", }; ``` @@ -53,11 +55,11 @@ exports.logger = { ```js // 将 logger 目录放到代码目录下 -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { logger: { - dir: path.join(appInfo.baseDir, 'logs'), + dir: path.join(appInfo.baseDir, "logs"), }, }; }; @@ -65,12 +67,12 @@ module.exports = (appInfo) => { 内置的 `appInfo` 属性包括: -| appInfo | 说明 | -| ------- | ------------------------------------------------------------ | -| pkg | `package.json` 文件 | -| name | 应用名称,同 `pkg.name` | -| baseDir | 应用代码的目录 | -| HOME | 用户目录,如 admin 账户为 `/home/admin` | +| appInfo | 说明 | +| ------- | -------------------------------------------------------------------------- | +| pkg | `package.json` 文件 | +| name | 应用名称,同 `pkg.name` | +| baseDir | 应用代码的目录 | +| HOME | 用户目录,如 admin 账户为 `/home/admin` | | root | 应用根目录,在 `local` 和 `unittest` 环境下为 `baseDir`,其他都为 `HOME`。 | `appInfo.root` 是一个优雅的适配方案。例如,在服务器环境我们通常使用 `/home/admin/logs` 作为日志目录,而在本地开发时为了避免污染用户目录,我们需要一种优雅的适配方案,`appInfo.root` 正好解决了这个问题。 @@ -79,10 +81,10 @@ module.exports = (appInfo) => { ```js // 配置文件 config/config.default.js -exports.someKeys = 'abc'; +exports.someKeys = "abc"; module.exports = (appInfo) => { const config = {}; - config.keys = '123456'; + config.keys = "123456"; return config; }; ``` @@ -103,6 +105,7 @@ module.exports = (appInfo) => { ``` **注意**:插件之间也会有加载顺序,但大致顺序类似。具体逻辑可[查看加载器](../advanced/loader.md)。 + ### 合并规则 配置的合并使用 `extend2` 模块进行深度拷贝,`extend2` 来源于 `extend`,但是在处理数组时的表现会有所不同。 diff --git a/site/docs/basics/controller.md b/site/docs/basics/controller.md index 02dcfaad27..2e2618baec 100644 --- a/site/docs/basics/controller.md +++ b/site/docs/basics/controller.md @@ -30,13 +30,13 @@ You can write a Controller by defining a Controller class: ```js // app/controller/post.js -const Controller = require('egg').Controller; +const Controller = require("egg").Controller; class PostController extends Controller { async create() { const { ctx, service } = this; const createRule = { - title: { type: 'string' }, - content: { type: 'string' }, + title: { type: "string" }, + content: { type: "string" }, }; // verify parameters ctx.validate(createRule); @@ -59,7 +59,7 @@ We've defined a `PostController` class above and every method of this Controller // app/router.js module.exports = (app) => { const { router, controller } = app; - router.post('createPost', '/api/posts', controller.post.create); + router.post("createPost", "/api/posts", controller.post.create); }; ``` @@ -68,7 +68,7 @@ Multi-level directory is supported, for example, put the above code into `app/co ```js // app/router.js module.exports = (app) => { - app.router.post('createPost', '/api/posts', app.controller.sub.post.create); + app.router.post("createPost", "/api/posts", app.controller.sub.post.create); }; ``` @@ -86,7 +86,7 @@ Defining a Controller class helps us not only abstract the Controller layer code ```js // app/core/base_controller.js -const { Controller } = require('egg'); +const { Controller } = require("egg"); class BaseController extends Controller { get user() { return this.ctx.session.user; @@ -100,7 +100,7 @@ class BaseController extends Controller { } notFound(msg) { - msg = msg || 'not found'; + msg = msg || "not found"; this.ctx.throw(404, msg); } } @@ -111,7 +111,7 @@ Now we can use base class' methods by inheriting from `BaseController`: ```js //app/controller/post.js -const Controller = require('../core/base_controller'); +const Controller = require("../core/base_controller"); class PostController extends Controller { async list() { const posts = await this.service.listByUser(this.user); @@ -130,8 +130,8 @@ For example, when we define a Controller relative to `POST /api/posts`, we creat // app/controller/post.js exports.create = async (ctx) => { const createRule = { - title: { type: 'string' }, - content: { type: 'string' }, + title: { type: "string" }, + content: { type: "string" }, }; // verify parameters ctx.validate(createRule); @@ -223,8 +223,8 @@ If duplicated keys exist in Query String, only the first value of this key is us This is for unity reason, because we usually do not design users to pass parameters with same keys in Query String then we write codes like below: ```js -const key = ctx.query.key || ''; -if (key.startsWith('egg')) { +const key = ctx.query.key || ""; +if (key.startsWith("egg")) { // do something } ``` @@ -259,8 +259,8 @@ In [Router](./router.md) part, we say Router is allowed to declare parameters wh // GET /projects/1/app/2 class AppController extends Controller { async listApp() { - assert.equal(this.ctx.params.projectId, '1'); - assert.equal(this.ctx.params.appId, '2'); + assert.equal(this.ctx.params.projectId, "1"); + assert.equal(this.ctx.params.appId, "2"); } } ``` @@ -284,8 +284,8 @@ The [bodyParser](https://github.com/koajs/bodyparser) middleware is built in by // {"title": "controller", "content": "what is controller"} class PostController extends Controller { async listPosts() { - assert.equal(this.ctx.request.body.title, 'controller'); - assert.equal(this.ctx.request.body.content, 'what is controller'); + assert.equal(this.ctx.request.body.title, "controller"); + assert.equal(this.ctx.request.body.content, "what is controller"); } } ``` @@ -301,8 +301,8 @@ The mostly adjusted config field is the maximum length of the request body for p ```js module.exports = { bodyParser: { - jsonLimit: '1mb', - formLimit: '1mb', + jsonLimit: "1mb", + formLimit: "1mb", }, }; ``` @@ -325,7 +325,7 @@ The `body` in the request can carry parameters as well as files. Generally speak ```js // config/config.default.js exports.multipart = { - mode: 'file', + mode: "file", }; ``` @@ -336,11 +336,7 @@ exports.multipart = { Your HTML static front-end codes should look like this below: ```html -
+ title: file:
@@ -350,14 +346,14 @@ The corresponding backend codes are: ```js // app/controller/upload.js -const Controller = require('egg').Controller; -const fs = require('fs/promises'); +const Controller = require("egg").Controller; +const fs = require("fs/promises"); module.exports = class extends Controller { async upload() { const { ctx } = this; const file = ctx.request.files[0]; - const name = 'egg-multipart-test/' + path.basename(file.filename); + const name = "egg-multipart-test/" + path.basename(file.filename); let result; try { // process file (e.g: upload to cloud storage) @@ -383,11 +379,7 @@ For multiple files, with the help of `ctx.request.files`, we can loop each of th Your HTML static front-end codes should look like this below: ```html -
+ title: file1: file2: @@ -398,27 +390,24 @@ The corresponding backend codes are: ```js // app/controller/upload.js -const Controller = require('egg').Controller; -const fs = require('fs/promises'); +const Controller = require("egg").Controller; +const fs = require("fs/promises"); module.exports = class extends Controller { async upload() { const { ctx } = this; console.log(ctx.request.body); - console.log('got %d files', ctx.request.files.length); + console.log("got %d files", ctx.request.files.length); for (const file of ctx.request.files) { - console.log('field: ' + file.fieldname); - console.log('filename: ' + file.filename); - console.log('encoding: ' + file.encoding); - console.log('mime: ' + file.mime); - console.log('tmp filepath: ' + file.filepath); + console.log("field: " + file.fieldname); + console.log("filename: " + file.filename); + console.log("encoding: " + file.encoding); + console.log("mime: " + file.mime); + console.log("tmp filepath: " + file.filepath); let result; try { // process file (e.g: upload to cloud storage) - result = await ctx.oss.put( - 'egg-multipart-test/' + file.filename, - file.filepath, - ); + result = await ctx.oss.put("egg-multipart-test/" + file.filename, file.filepath); } finally { // need to remove the tmp file await fs.unlink(file.filepath); @@ -435,26 +424,22 @@ module.exports = class extends Controller { 1. For Single File: ```html - + title: file:
``` ```js -const path = require('path'); -const sendToWormhole = require('stream-wormhole'); -const Controller = require('egg').Controller; +const path = require("path"); +const sendToWormhole = require("stream-wormhole"); +const Controller = require("egg").Controller; class UploaderController extends Controller { async upload() { const ctx = this.ctx; const stream = await ctx.getFileStream(); - const name = 'egg-multipart-test/' + path.basename(stream.filename); + const name = "egg-multipart-test/" + path.basename(stream.filename); let result; try { // process file (e.g: upload to cloud storage) @@ -486,8 +471,8 @@ To acquire the uploaded files easily, there're two conditions at least: For multiple files, you should do the following instead of using `ctx.getFileStream()`: ```js -const sendToWormhole = require('stream-wormhole'); -const Controller = require('egg').Controller; +const sendToWormhole = require("stream-wormhole"); +const Controller = require("egg").Controller; class UploaderController extends Controller { async upload() { @@ -498,10 +483,10 @@ class UploaderController extends Controller { while ((part = await parts()) != null) { if (part.length) { // arrays are busboy fields - console.log('field: ' + part[0]); - console.log('value: ' + part[1]); - console.log('valueTruncated: ' + part[2]); - console.log('fieldnameTruncated: ' + part[3]); + console.log("field: " + part[0]); + console.log("value: " + part[1]); + console.log("valueTruncated: " + part[2]); + console.log("fieldnameTruncated: " + part[3]); } else { if (!part.filename) { // When a user clicks `upload` before choosing a file, @@ -511,17 +496,14 @@ class UploaderController extends Controller { return; } // otherwise, it's a fully-filled stream - console.log('field: ' + part.fieldname); - console.log('filename: ' + part.filename); - console.log('encoding: ' + part.encoding); - console.log('mime: ' + part.mime); + console.log("field: " + part.fieldname); + console.log("filename: " + part.filename); + console.log("encoding: " + part.encoding); + console.log("mime: " + part.mime); let result; try { // process file (e.g: upload to cloud storage) - result = await ctx.oss.put( - 'egg-multipart-test/' + part.filename, - part, - ); + result = await ctx.oss.put("egg-multipart-test/" + part.filename, part); } catch (err) { // You MUST consume the file stream, otherwises the browser cannot response any more await sendToWormhole(part); @@ -530,7 +512,7 @@ class UploaderController extends Controller { console.log(result); } } - console.log('and we are done parsing the form!'); + console.log("and we are done parsing the form!"); } } @@ -572,7 +554,7 @@ Users can add new file extensions in `config/config.default.js`, or rewrite a wh ```js module.exports = { multipart: { - fileExtensions: ['.apk'], // Add support for apk files + fileExtensions: [".apk"], // Add support for apk files }, }; ``` @@ -582,7 +564,7 @@ module.exports = { ```js module.exports = { multipart: { - whitelist: ['.png'], // ONLY files of png is allowed + whitelist: [".png"], // ONLY files of png is allowed }, }; ``` @@ -640,15 +622,15 @@ Through `ctx.cookies`, we can conveniently and safely set and get Cookie in Cont class CookieController extends Controller { async add() { const ctx = this.ctx; - let count = ctx.cookies.get('count'); + let count = ctx.cookies.get("count"); count = count ? Number(count) : 0; - ctx.cookies.set('count', ++count); + ctx.cookies.set("count", ++count); ctx.body = count; } async remove() { const ctx = this.ctx; - const count = ctx.cookies.set('count', null); + const count = ctx.cookies.set("count", null); ctx.status = 204; } } @@ -676,7 +658,7 @@ e.g.: Configured application level Cookie [SameSite](https://www.ruanyifeng.com/ ```js module.exports = { cookies: { - sameSite: 'lax', + sameSite: "lax", }, }; ``` @@ -722,7 +704,7 @@ There are mainly these attributes below can be used to configure Session in `con ```js module.exports = { - key: 'EGG_SESS', // the name of key-value pairs, which is specially used by Cookie to store Session + key: "EGG_SESS", // the name of key-value pairs, which is specially used by Cookie to store Session maxAge: 86400000, // Session maximum valid time }; ``` @@ -737,7 +719,7 @@ With the help of the convenient parameter validation mechanism provided by [Vali // config/plugin.js exports.validate = { enable: true, - package: 'egg-validate', + package: "egg-validate", }; ``` @@ -749,8 +731,8 @@ class PostController extends Controller { // validate parameters // if the second parameter is absent, `ctx.request.body` is validated automatically this.ctx.validate({ - title: { type: 'string' }, - content: { type: 'string' }, + title: { type: "string" }, + content: { type: "string" }, }); } } @@ -783,11 +765,11 @@ In addition to built-in validation types introduced in the previous section, som ```js // app.js -app.validator.addRule('json', (rule, value) => { +app.validator.addRule("json", (rule, value) => { try { JSON.parse(value); } catch (err) { - return 'must be json string'; + return "must be json string"; } }); ``` @@ -799,7 +781,7 @@ class PostController extends Controller { async handler() { const ctx = this.ctx; // query.test field must be a json string - const rule = { test: 'json' }; + const rule = { test: "json" }; ctx.validate(rule, ctx.query); } } @@ -861,14 +843,14 @@ Most data is sent to requesters through the body and, just like the body in the class ViewController extends Controller { async show() { this.ctx.body = { - name: 'egg', - category: 'framework', - language: 'Node.js', + name: "egg", + category: "framework", + language: "Node.js", }; } async page() { - this.ctx.body = '

Hello

'; + this.ctx.body = "

Hello

"; } } ``` @@ -898,7 +880,7 @@ Egg itself does not integrate any template engine, but it establishes the [View class HomeController extends Controller { async index() { const ctx = this.ctx; - await ctx.render('home.tpl', { name: 'egg' }); + await ctx.render("home.tpl", { name: "egg" }); // ctx.body = await ctx.renderString('hi, {{ name }}', { name: 'egg' }); } } @@ -918,8 +900,8 @@ Since misuse of JSONP leads to dozens of security issues, the framework supplies // app/router.js module.exports = (app) => { const jsonp = app.jsonp(); - app.router.get('/api/posts/:id', jsonp, app.controller.posts.show); - app.router.get('/api/posts', jsonp, app.controller.posts.list); + app.router.get("/api/posts/:id", jsonp, app.controller.posts.show); + app.router.get("/api/posts", jsonp, app.controller.posts.list); }; ``` @@ -930,9 +912,9 @@ module.exports = (app) => { class PostController extends Controller { async show() { this.ctx.body = { - name: 'egg', - category: 'framework', - language: 'Node.js', + name: "egg", + category: "framework", + language: "Node.js", }; } } @@ -947,7 +929,7 @@ By default, the framework determines whether to return data in JSONP format or n ```js // config/config.default.js exports.jsonp = { - callback: 'callback', // inspecting the `callback` parameter in the query + callback: "callback", // inspecting the `callback` parameter in the query limit: 100, // the maximum size of the method name is 100 characters }; ``` @@ -960,12 +942,8 @@ Also we can overwrite the default configuration in `app.jsonp()` when creating t // app/router.js module.exports = (app) => { const { router, controller, jsonp } = app; - router.get( - '/api/posts/:id', - jsonp({ callback: 'callback' }), - controller.posts.show, - ); - router.get('/api/posts', jsonp({ callback: 'cb' }), controller.posts.list); + router.get("/api/posts/:id", jsonp({ callback: "callback" }), controller.posts.show); + router.get("/api/posts", jsonp({ callback: "cb" }), controller.posts.list); }; ``` @@ -1027,7 +1005,7 @@ exports.jsonp = { ```js exports.jsonp = { - whiteList: '.test.com', + whiteList: ".test.com", }; // matches domain test.com: // https://test.com/hello @@ -1038,7 +1016,7 @@ exports.jsonp = { // http://sub.sub.test.com/ exports.jsonp = { - whiteList: 'sub.test.com', + whiteList: "sub.test.com", }; // only matches domain sub.test.com: // https://sub.test.com/hello @@ -1049,7 +1027,7 @@ exports.jsonp = { ```js exports.jsonp = { - whiteList: ['sub.test.com', 'sub2.test.com'], + whiteList: ["sub.test.com", "sub2.test.com"], }; // matches domain sub.test.com and sub2.test.com: // https://sub.test.com/hello @@ -1073,7 +1051,7 @@ class ProxyController extends Controller { ctx.body = await ctx.service.post.get(); const used = Date.now() - start; // set one response header - ctx.set('show-response-time', used.toString()); + ctx.set("show-response-time", used.toString()); } } ``` @@ -1090,7 +1068,7 @@ If you use the `ctx.redirect` method, you need to configure the application conf ```js // config/config.default.js exports.security = { - domainWhiteList: ['.domain.com'], // Security whitelist, starts with `.` + domainWhiteList: [".domain.com"], // Security whitelist, starts with `.` }; ``` diff --git a/site/docs/basics/controller.zh-CN.md b/site/docs/basics/controller.zh-CN.md index bed3b21d76..ce4c976b42 100644 --- a/site/docs/basics/controller.zh-CN.md +++ b/site/docs/basics/controller.zh-CN.md @@ -19,6 +19,7 @@ order: 7 2. 校验、组装参数。 3. 调用 Service 进行业务处理,必要时处理转换 Service 的返回结果,让它适应用户的需求。 4. 通过 HTTP 将结果响应给用户。 + ## 如何编写 Controller 所有的 Controller 文件都必须放在 `app/controller` 目录下,可以支持多级目录,访问的时候可以通过目录名级联访问。Controller 支持多种形式进行编写,可以根据不同的项目场景和开发习惯来选择。 @@ -29,13 +30,13 @@ order: 7 ```javascript // app/controller/post.js -const Controller = require('egg').Controller; +const Controller = require("egg").Controller; class PostController extends Controller { async create() { const { ctx, service } = this; const createRule = { - title: { type: 'string' }, - content: { type: 'string' }, + title: { type: "string" }, + content: { type: "string" }, }; // 校验参数 ctx.validate(createRule); @@ -58,7 +59,7 @@ module.exports = PostController; // app/router.js module.exports = (app) => { const { router, controller } = app; - router.post('createPost', '/api/posts', controller.post.create); + router.post("createPost", "/api/posts", controller.post.create); }; ``` @@ -66,8 +67,8 @@ Controller 支持多级目录。例如,如果我们将上面的 Controller 代 ```javascript // app/router.js -module.exports = app => { - app.router.post('createPost', '/api/posts', app.controller.sub.post.create); +module.exports = (app) => { + app.router.post("createPost", "/api/posts", app.controller.sub.post.create); }; ``` @@ -85,7 +86,7 @@ module.exports = app => { ```javascript // app/core/base_controller.js -const { Controller } = require('egg'); +const { Controller } = require("egg"); class BaseController extends Controller { get user() { return this.ctx.session.user; @@ -99,7 +100,7 @@ class BaseController extends Controller { } notFound(msg) { - msg = msg || 'not found'; + msg = msg || "not found"; this.ctx.throw(404, msg); } } @@ -110,7 +111,7 @@ module.exports = BaseController; ```javascript // app/controller/post.js -const Controller = require('../core/base_controller'); +const Controller = require("../core/base_controller"); class PostController extends Controller { async list() { const posts = await this.service.listByUser(this.user); @@ -127,10 +128,10 @@ class PostController extends Controller { ```javascript // app/controller/post.js -exports.create = async ctx => { +exports.create = async (ctx) => { const createRule = { - title: { type: 'string' }, - content: { type: 'string' }, + title: { type: "string" }, + content: { type: "string" }, }; // 校验参数 ctx.validate(createRule); @@ -146,6 +147,7 @@ exports.create = async ctx => { ``` 以上是一个简单直观的例子,我们引入了一些新的概念,但它们都是易于理解的。我们将在后面对它们进行更详细的介绍。 + ## HTTP 基础 由于控制器(Controller)基本上是业务开发中唯一与 HTTP 协议打交道的地方,在继续深入了解之前,我们首先要简单了解一下 HTTP 协议本身。 @@ -195,6 +197,7 @@ Connection: keep-alive 响应头从第二行至下一个空行,这里的 Content-Type 和 Content-Length 表明响应格式为 JSON,长度 8 字节。 最后部分即响应实际内容。 + ## 获取 HTTP 请求参数 从上述 HTTP 请求示例中, 我们可以看到, 多个位置可以放置用户的请求数据。框架通过在 Controller 上绑定的 Context 实例, 提供了多种便捷方法和属性, 以获取用户通过 HTTP 请求发送过来的参数。 @@ -221,8 +224,8 @@ class PostController extends Controller { 之所以这样处理是为了保持一致性。一般我们不会设计让用户传递相同 key 的 Query String,所以经常编写如下代码: ```js -const key = ctx.query.key || ''; -if (key.startsWith('egg')) { +const key = ctx.query.key || ""; +if (key.startsWith("egg")) { // 执行相应操作 } ``` @@ -258,8 +261,8 @@ class PostController extends Controller { // GET /projects/1/app/2 class AppController extends Controller { async listApp() { - assert.equal(this.ctx.params.projectId, '1'); - assert.equal(this.ctx.params.appId, '2'); + assert.equal(this.ctx.params.projectId, "1"); + assert.equal(this.ctx.params.appId, "2"); } } ``` @@ -283,8 +286,8 @@ class AppController extends Controller { // {"title": "controller", "content": "what is controller"} class PostController extends Controller { async listPosts() { - assert.equal(this.ctx.request.body.title, 'controller'); - assert.equal(this.ctx.request.body.content, 'what is controller'); + assert.equal(this.ctx.request.body.title, "controller"); + assert.equal(this.ctx.request.body.content, "what is controller"); } } ``` @@ -300,8 +303,8 @@ class PostController extends Controller { ```js module.exports = { bodyParser: { - jsonLimit: '1mb', - formLimit: '1mb', + jsonLimit: "1mb", + formLimit: "1mb", }, }; ``` @@ -311,6 +314,7 @@ module.exports = { **注意:调整 bodyParser 支持的 body 长度时,如果应用之前有一层反向代理(如 Nginx),同样需要调整配置确保支持相等长度的请求 body。** **常见错误:将 `ctx.request.body` 与 `ctx.body` 混淆,后者实际上是 `ctx.response.body` 的简写。** + ### 获取上传的文件 请求体除了可以带参数之外,还可以发送文件。通常情况下,浏览器会通过 `Multipart/form-data` 格式发送文件。通过内置的 [Multipart](https://github.com/eggjs/egg-multipart) 插件,框架支持获取用户上传的文件。我们为你提供了两种方式: @@ -324,7 +328,7 @@ module.exports = { ```javascript // config/config.default.js exports.multipart = { - mode: 'file', + mode: "file", }; ``` @@ -336,8 +340,7 @@ exports.multipart = { ```html
- title: - file: + title: file:
``` @@ -346,15 +349,15 @@ exports.multipart = { ```javascript // app/controller/upload.js -const Controller = require('egg').Controller; -const fs = require('fs/promises'); -const path = require('path'); // 补上缺失的 path 模块 +const Controller = require("egg").Controller; +const fs = require("fs/promises"); +const path = require("path"); // 补上缺失的 path 模块 class UploadController extends Controller { async upload() { const { ctx } = this; const file = ctx.request.files[0]; - const name = 'egg-multipart-test/' + path.basename(file.filename); + const name = "egg-multipart-test/" + path.basename(file.filename); let result; try { // 处理文件,例如上传到云采存储 @@ -381,9 +384,8 @@ module.exports = UploadController; ```html
- title: - file1: - file2: + title: file1: file2: +
``` @@ -392,9 +394,9 @@ module.exports = UploadController; ```javascript // app/controller/upload.js -const Controller = require('egg').Controller; -const fs = require('fs/promises'); -const path = require('path'); // 补上缺失的 path 模块 +const Controller = require("egg").Controller; +const fs = require("fs/promises"); +const path = require("path"); // 补上缺失的 path 模块 class UploadController extends Controller { async upload() { @@ -410,10 +412,7 @@ class UploadController extends Controller { let result; try { // 处理文件,例如上传到云采存储 - result = await ctx.oss.put( - 'egg-multipart-test/' + file.filename, - file.filepath, - ); + result = await ctx.oss.put("egg-multipart-test/" + file.filename, file.filepath); } finally { // 注意删除临时文件 await fs.unlink(file.filepath); @@ -427,6 +426,7 @@ module.exports = UploadController; ``` 以上代码包涵了前端的表单代码以及后端处理上传文件的代码。在服务器端,我们首先获取上传文件的信息,然后将文件上传到指定的储存系统,例如云储存。随后,我们确保了临时文件被删除,防止占用服务器空间。 + #### Stream 模式 如果你对 Node 中的 Stream 模式非常熟悉,那么你可以选择此模式。在 Controller 中,我们可以通过 `ctx.getFileStream()` 接口获取到上传的文件流。 @@ -435,7 +435,7 @@ module.exports = UploadController; ```html
- title: file: + title: file:
``` @@ -481,8 +481,8 @@ module.exports = UploaderController; 如果要获取同时上传的多个文件,不能通过 `ctx.getFileStream()` 来获取,只能通过下面这种方式: ```js -const sendToWormhole = require('stream-wormhole'); -const Controller = require('egg').Controller; +const sendToWormhole = require("stream-wormhole"); +const Controller = require("egg").Controller; class UploaderController extends Controller { async upload() { @@ -493,10 +493,10 @@ class UploaderController extends Controller { while ((part = await parts()) != null) { if (part.length) { // 这是 busboy 的字段 - console.log('field:' + part[0]); - console.log('value:' + part[1]); - console.log('valueTruncated:' + part[2]); - console.log('fieldnameTruncated:' + part[3]); + console.log("field:" + part[0]); + console.log("value:" + part[1]); + console.log("valueTruncated:" + part[2]); + console.log("fieldnameTruncated:" + part[3]); } else { if (!part.filename) { // 这时是用户没有选择文件就点击了上传(part 是 file stream,但是 part.filename 为空) @@ -504,14 +504,14 @@ class UploaderController extends Controller { return; } // part 是上传的文件流 - console.log('field:' + part.fieldname); - console.log('filename:' + part.filename); - console.log('encoding:' + part.encoding); - console.log('mime:' + part.mime); + console.log("field:" + part.fieldname); + console.log("filename:" + part.filename); + console.log("encoding:" + part.encoding); + console.log("mime:" + part.mime); // 文件处理,上传到云存储等等 let result; try { - result = await ctx.oss.put('egg-multipart-test/' + part.filename, part); + result = await ctx.oss.put("egg-multipart-test/" + part.filename, part); } catch (err) { // 必须将上传的文件流消费掉,要不然浏览器响应会卡死 await sendToWormhole(part); @@ -520,7 +520,7 @@ class UploaderController extends Controller { console.log(result); } } - console.log('and we are done parsing the form!'); + console.log("and we are done parsing the form!"); } } @@ -531,28 +531,34 @@ module.exports = UploaderController; ```js // images -'.jpg', '.jpeg', // image/jpeg -'.png', // image/png,image/x-png -'.gif', // image/gif -'.bmp', // image/bmp -'.wbmp', // image/vnd.wap.wbmp -'.webp', -'.tif', -'.psd', -// text -'.svg', -'.js', '.jsx', -'.json', -'.css', '.less', -'.html', '.htm', -'.xml', -// tar -'.zip', -'.gz', '.tgz', '.gzip', -// video -'.mp3', -'.mp4', -'.avi' +(".jpg", + ".jpeg", // image/jpeg + ".png", // image/png,image/x-png + ".gif", // image/gif + ".bmp", // image/bmp + ".wbmp", // image/vnd.wap.wbmp + ".webp", + ".tif", + ".psd", + // text + ".svg", + ".js", + ".jsx", + ".json", + ".css", + ".less", + ".html", + ".htm", + ".xml", + // tar + ".zip", + ".gz", + ".tgz", + ".gzip", + // video + ".mp3", + ".mp4", + ".avi"); ``` 用户可以通过在 `config/config.default.js` 中的配置来新增支持的文件扩展名,或者重写整个白名单。 @@ -562,8 +568,8 @@ module.exports = UploaderController; ```js module.exports = { multipart: { - fileExtensions: ['.apk'] // 增加对 '.apk' 扩展名的文件支持 - } + fileExtensions: [".apk"], // 增加对 '.apk' 扩展名的文件支持 + }, }; ``` @@ -572,14 +578,15 @@ module.exports = { ```js module.exports = { multipart: { - whitelist: ['.png'] // 覆盖整个白名单,只允许上传 '.png' 格式 - } + whitelist: [".png"], // 覆盖整个白名单,只允许上传 '.png' 格式 + }, }; ``` **注意:当重写了 whitelist 时,fileExtensions 不生效。** 欲了解更多有关的技术细节和信息,请参阅 [Egg-Multipart](https://github.com/eggjs/egg-multipart)。 + ### Header 除了从 URL 和请求 body 上获取参数之外,还有许多参数是通过请求 header 传递的。框架提供了一些辅助属性和方法来获取: @@ -629,15 +636,15 @@ HTTP 请求本质上是无状态的,但 Web 应用通常需要知道请求者 class CookieController extends Controller { async add() { const ctx = this.ctx; - let count = ctx.cookies.get('count'); + let count = ctx.cookies.get("count"); count = count ? Number(count) : 0; - ctx.cookies.set('count', ++count); + ctx.cookies.set("count", ++count); ctx.body = count; } async remove() { const ctx = this.ctx; - ctx.cookies.set('count', null); + ctx.cookies.set("count", null); ctx.status = 204; } } @@ -663,7 +670,7 @@ module.exports = { ```js module.exports = { cookies: { - sameSite: 'lax', + sameSite: "lax", }, }; ``` @@ -709,10 +716,11 @@ Session 相关配置也位于 `config.default.js`: ```js module.exports = { - key: 'EGG_SESS', // Session Cookie 名称 + key: "EGG_SESS", // Session Cookie 名称 maxAge: 86400000, // Session 最长有效期 }; ``` + ## 参数校验 在获取用户请求的参数后,不可避免要进行一些校验。 @@ -723,7 +731,7 @@ module.exports = { // config/plugin.js exports.validate = { enable: true, - package: 'egg-validate', + package: "egg-validate", }; ``` @@ -735,8 +743,8 @@ class PostController extends Controller { // 校验参数 // 如果不传第二个参数,会自动校验 `ctx.request.body` this.ctx.validate({ - title: { type: 'string' }, - content: { type: 'string' } + title: { type: "string" }, + content: { type: "string" }, }); } } @@ -769,11 +777,11 @@ class PostController extends Controller { ```js // app.js -app.validator.addRule('json', (rule, value) => { +app.validator.addRule("json", (rule, value) => { try { JSON.parse(value); } catch (err) { - return '必须是 JSON 字符串'; + return "必须是 JSON 字符串"; } }); ``` @@ -785,7 +793,7 @@ class PostController extends Controller { async handler() { const ctx = this.ctx; // query.test 字段必须是 JSON 字符串 - const rule = { test: 'json' }; + const rule = { test: "json" }; ctx.validate(rule, ctx.query); } } @@ -812,6 +820,7 @@ class PostController extends Controller { ``` Service 具体写法,查看 [Service](./service.md) 章节。 + ## 发送 HTTP 响应 当业务逻辑完成之后,Controller 的最后一个职责就是将业务逻辑的处理结果通过 HTTP 响应发送给用户。 @@ -846,14 +855,14 @@ class PostController extends Controller { class ViewController extends Controller { async show() { this.ctx.body = { - name: 'egg', - category: 'framework', - language: 'Node.js' + name: "egg", + category: "framework", + language: "Node.js", }; } async page() { - this.ctx.body = '

Hello

'; + this.ctx.body = "

Hello

"; } } ``` @@ -865,7 +874,7 @@ class ProxyController extends Controller { async proxy() { const ctx = this.ctx; const result = await ctx.curl(url, { - streaming: true + streaming: true, }); ctx.set(result.header); // result.res 是一个 stream @@ -882,7 +891,7 @@ class ProxyController extends Controller { class HomeController extends Controller { async index() { const ctx = this.ctx; - await ctx.render('home.tpl', { name: 'egg' }); + await ctx.render("home.tpl", { name: "egg" }); // ctx.body = await ctx.renderString('hi, {{ name }}', { name: 'egg' }); } } @@ -900,10 +909,10 @@ class HomeController extends Controller { ```js // app/router.js -module.exports = app => { +module.exports = (app) => { const jsonp = app.jsonp(); - app.router.get('/api/posts/:id', jsonp, app.controller.posts.show); - app.router.get('/api/posts', jsonp, app.controller.posts.list); + app.router.get("/api/posts/:id", jsonp, app.controller.posts.show); + app.router.get("/api/posts", jsonp, app.controller.posts.list); }; ``` @@ -914,9 +923,9 @@ module.exports = app => { class PostController extends Controller { async show() { this.ctx.body = { - name: 'egg', - category: 'framework', - language: 'Node.js' + name: "egg", + category: "framework", + language: "Node.js", }; } } @@ -931,8 +940,8 @@ class PostController extends Controller { ```js // config/config.default.js exports.jsonp = { - callback: 'callback', // 识别 query 中的 `callback` 参数 - limit: 100 // 函数名最长为 100 个字符 + callback: "callback", // 识别 query 中的 `callback` 参数 + limit: 100, // 函数名最长为 100 个字符 }; ``` @@ -942,14 +951,10 @@ exports.jsonp = { ```js // app/router.js -module.exports = app => { +module.exports = (app) => { const { router, controller, jsonp } = app; - router.get( - '/api/posts/:id', - jsonp({ callback: 'callback' }), - controller.posts.show - ); - router.get('/api/posts', jsonp({ callback: 'cb' }), controller.posts.list); + router.get("/api/posts/:id", jsonp({ callback: "callback" }), controller.posts.show); + router.get("/api/posts", jsonp({ callback: "cb" }), controller.posts.list); }; ``` @@ -971,8 +976,8 @@ module.exports = app => { // config/config.default.js module.exports = { jsonp: { - csrf: true - } + csrf: true, + }, }; ``` @@ -987,7 +992,7 @@ module.exports = { ```javascript // config/config.default.js exports.jsonp = { - whiteList: /^https?:\/\/test.com\// + whiteList: /^https?:\/\/test.com\//, // whiteList: '.test.com' // whiteList: 'sub.test.com' // whiteList: ['sub.test.com', 'sub2.test.com'] @@ -1000,7 +1005,7 @@ exports.jsonp = { ```javascript exports.jsonp = { - whiteList: /^https?:\/\/test.com\// + whiteList: /^https?:\/\/test.com\//, }; // Matches referrer: // https://test.com/hello @@ -1011,7 +1016,7 @@ exports.jsonp = { ```javascript exports.jsonp = { - whiteList: '.test.com' + whiteList: ".test.com", }; // Matches domain test.com: // https://test.com/hello @@ -1022,7 +1027,7 @@ exports.jsonp = { // http://sub.sub.test.com/ exports.jsonp = { - whiteList: 'sub.test.com' + whiteList: "sub.test.com", }; // Only matches domain sub.test.com: // https://sub.test.com/hello @@ -1033,7 +1038,7 @@ exports.jsonp = { ```javascript exports.jsonp = { - whiteList: ['sub.test.com', 'sub2.test.com'] + whiteList: ["sub.test.com", "sub2.test.com"], }; // Matches domain sub.test.com and sub2.test.com: // https://sub.test.com/hello @@ -1057,7 +1062,7 @@ class ProxyController extends Controller { ctx.body = await ctx.service.post.get(); const used = Date.now() - start; // 设置一个响应头 - ctx.set('show-response-time', used.toString()); + ctx.set("show-response-time", used.toString()); } } ``` @@ -1074,7 +1079,7 @@ class ProxyController extends Controller { ```javascript // config/config.default.js exports.security = { - domainWhiteList: ['.domain.com'] // 安全白名单,以 "." 开头 + domainWhiteList: [".domain.com"], // 安全白名单,以 "." 开头 }; ``` diff --git a/site/docs/basics/env.zh-CN.md b/site/docs/basics/env.zh-CN.md index f67b41b205..cb70916451 100644 --- a/site/docs/basics/env.zh-CN.md +++ b/site/docs/basics/env.zh-CN.md @@ -25,22 +25,25 @@ EGG_SERVER_ENV=prod npm start ## 应用内获取运行环境 框架提供了变量 `app.config.env`,来表示应用当前的运行环境。 + ## 运行环境相关配置 不同的运行环境会对应不同的配置,具体请阅读 [Config 配置](./config.md)。 + ## 与 `NODE_ENV` 的区别 很多 Node.js 应用会使用 `NODE_ENV` 来区分运行环境,但 `EGG_SERVER_ENV` 区分得更加精细。一般的项目开发流程包括本地开发环境、测试环境、生产环境等,除了本地开发环境和测试环境外,其他环境可统称为**服务器环境**。服务器环境的 `NODE_ENV` 应该为 `production`。而且 npm 也会使用这个变量,在应用部署时,一般不会安装 devDependencies,所以这个值也应该为 `production`。 框架默认支持的运行环境及映射关系(如果未指定 `EGG_SERVER_ENV`,会根据 `NODE_ENV` 来匹配)如下表所示: -| `NODE_ENV` | `EGG_SERVER_ENV` | 说明 | -|--------------|------------------|--------------| -| (不设置) | local | 本地开发环境 | -| test | unittest | 单元测试 | -| production | prod | 生产环境 | +| `NODE_ENV` | `EGG_SERVER_ENV` | 说明 | +| ---------- | ---------------- | ------------ | +| (不设置) | local | 本地开发环境 | +| test | unittest | 单元测试 | +| production | prod | 生产环境 | 例如,当 `NODE_ENV` 为 `production` 而 `EGG_SERVER_ENV` 未指定时,框架会将 `EGG_SERVER_ENV` 设置成 `prod`。 + ## 自定义环境 Egg 框架支持开发者根据实际需要自定义开发环境。 diff --git a/site/docs/basics/extend.md b/site/docs/basics/extend.md index a293605d57..f77fb53bd3 100644 --- a/site/docs/basics/extend.md +++ b/site/docs/basics/extend.md @@ -57,7 +57,7 @@ For example, if we would like to add a Getter property `app.bar`: ```js // app/extend/application.js -const BAR = Symbol('Application#bar'); +const BAR = Symbol("Application#bar"); module.exports = { get bar() { @@ -108,14 +108,14 @@ For example, if we would like to add a Getter property `ctx.bar`: ```js // app/extend/context.js -const BAR = Symbol('Context#bar'); +const BAR = Symbol("Context#bar"); module.exports = { get bar() { // `this` points to the ctx object, you can access other methods or property of ctx if (!this[BAR]) { // For example, we can get from header, but it should be more complex in real situation. - this[BAR] = this.get('x-bar'); + this[BAR] = this.get("x-bar"); } return this[BAR]; }, @@ -146,7 +146,7 @@ For instance, we could add a property `request.foo` in the following way: // app/extend/request.js module.exports = { get foo() { - return this.get('x-request-foo'); + return this.get("x-request-foo"); }, }; ``` @@ -175,7 +175,7 @@ For instance, we could add a setter `request.foo` in the following way: // app/extend/response.js module.exports = { set foo(value) { - this.set('x-response-foo', value); + this.set("x-response-foo", value); }, }; ``` @@ -196,10 +196,10 @@ Access helper object with `ctx.helper`, for example: ```js // Assume that home router has already defined in app/router.js -app.get('home', '/', 'home.index'); +app.get("home", "/", "home.index"); // Use helper to calculate the specific url path -ctx.helper.pathFor('home', { by: 'recent', limit: 20 }); +ctx.helper.pathFor("home", { by: "recent", limit: 20 }); // => /?by=recent&limit=20 ``` diff --git a/site/docs/basics/extend.zh-CN.md b/site/docs/basics/extend.zh-CN.md index 6ba5acf684..b526a836d3 100644 --- a/site/docs/basics/extend.zh-CN.md +++ b/site/docs/basics/extend.zh-CN.md @@ -20,7 +20,7 @@ order: 11 ### 访问方式 - `ctx.app` - + `ctx.app` 提供了一种访问全局 `app` 对象的方式。 - Controller,Middleware,Helper,Service 中都可以通过 `this.app` 访问到 Application 对象。例如,通过 `this.app.config` 可以访问配置对象。 @@ -29,7 +29,7 @@ order: 11 ```js // app.js -module.exports = app => { +module.exports = (app) => { // 使用 app 对象 }; ``` @@ -61,7 +61,7 @@ module.exports = { ```js // app/extend/application.js -const BAR = Symbol('Application#bar'); +const BAR = Symbol("Application#bar"); module.exports = { get bar() { @@ -74,6 +74,7 @@ module.exports = { }, }; ``` + ## Context Context 指的是 Koa 的请求上下文,这是请求级别的对象,每次请求生成一个 Context 实例,通常我们也简写成 `ctx`。在所有的文档中,Context 和 `ctx` 都是指 Koa 的上下文对象。 @@ -97,7 +98,7 @@ Context 指的是 Koa 的请求上下文,这是请求级别的对象,每次 module.exports = { foo(param) { // this 就是 ctx 对象,在其中可以调用 ctx 上的其他方法,或访问属性 - } + }, }; ``` @@ -111,19 +112,20 @@ module.exports = { ```js // app/extend/context.js -const BAR = Symbol('Context#bar'); +const BAR = Symbol("Context#bar"); module.exports = { get bar() { // this 就是 ctx 对象,在其中可以调用 ctx 上的其他方法,或访问属性 if (!this[BAR]) { // 例如,从 header 中获取,实际情况肯定更复杂 - this[BAR] = this.get('x-bar'); + this[BAR] = this.get("x-bar"); } return this[BAR]; - } + }, }; ``` + ## Request 对象 Request 对象和 Koa 的 Request 对象相同,是 **请求级别** 的对象,它提供了大量请求相关的属性和方法供使用。 @@ -148,7 +150,7 @@ Koa 内置的代理 `request` 的属性和方法列表可参阅:[Koa - Request // app/extend/request.js module.exports = { get foo() { - return this.get('x-request-foo'); + return this.get("x-request-foo"); }, }; ``` @@ -177,7 +179,7 @@ ctx.response; // app/extend/response.js module.exports = { set foo(value) { - this.set('x-response-foo', value); + this.set("x-response-foo", value); }, }; ``` @@ -198,10 +200,10 @@ Helper 函数用来提供一些实用的 utility 函数。 ```js // 假设在 app/router.js 中定义了 home router -app.get('home', '/', 'home.index'); +app.get("home", "/", "home.index"); // 使用 helper 计算指定 url path -ctx.helper.pathFor('home', { by: 'recent', limit: 20 }); +ctx.helper.pathFor("home", { by: "recent", limit: 20 }); // => /?by=recent&limit=20 ``` diff --git a/site/docs/basics/middleware.md b/site/docs/basics/middleware.md index ba286c521d..e8a9711fc0 100644 --- a/site/docs/basics/middleware.md +++ b/site/docs/basics/middleware.md @@ -12,8 +12,8 @@ In [the previous chapter](../intro/egg-and-koa.md), we say that Egg is based on Let's take a look at how to write a middleware from a simple gzip example. ```js -const isJSON = require('koa-is-json'); -const zlib = require('zlib'); +const isJSON = require("koa-is-json"); +const zlib = require("zlib"); async function gzip(ctx, next) { await next(); @@ -27,7 +27,7 @@ async function gzip(ctx, next) { const stream = zlib.createGzip(); stream.end(body); ctx.body = stream; - ctx.set('Content-Encoding', 'gzip'); + ctx.set("Content-Encoding", "gzip"); } ``` @@ -44,8 +44,8 @@ We will do a simple optimization to the gzip middleware above, making it do gzip ```js // app/middleware/gzip.js -const isJSON = require('koa-is-json'); -const zlib = require('zlib'); +const isJSON = require("koa-is-json"); +const zlib = require("zlib"); module.exports = (options) => { return async function gzip(ctx, next) { @@ -64,7 +64,7 @@ module.exports = (options) => { const stream = zlib.createGzip(); stream.end(body); ctx.body = stream; - ctx.set('Content-Encoding', 'gzip'); + ctx.set("Content-Encoding", "gzip"); }; }; ``` @@ -82,7 +82,7 @@ we can edit `config.default.js` like this: ```js module.exports = { // configure the middleware you need, which loads in the order of array - middleware: ['gzip'], + middleware: ["gzip"], // configure the gzip middleware gzip: { @@ -101,7 +101,7 @@ Framework and Plugin don't support to configure `middleware` in `config.default. // app.js module.exports = (app) => { // put to the first place to count request cost - app.config.coreMiddleware.unshift('report'); + app.config.coreMiddleware.unshift("report"); }; // app/middleware/report.js @@ -125,7 +125,7 @@ If you do want to take effect only for single route, you could just instantiate ```js module.exports = (app) => { const gzip = app.middleware.gzip({ threshold: 1024 }); - app.router.get('/needgzip', gzip, app.controller.handler); + app.router.get("/needgzip", gzip, app.controller.handler); }; ``` @@ -136,7 +136,7 @@ In addition to application layer loading middleware, the framework itself and ot ```js module.exports = { bodyParser: { - jsonLimit: '10m', + jsonLimit: "10m", }, }; ``` @@ -150,8 +150,8 @@ Developer is free to use Koa Middleware, all middlewares used in Koa can be dire For example, Koa uses [koa-compress](https://github.com/koajs/compress) in this way: ```js -const koa = require('koa'); -const compress = require('koa-compress'); +const koa = require("koa"); +const compress = require("koa-compress"); const app = koa(); @@ -164,13 +164,13 @@ We can load the middleware according to the framework specification like this: ```js // app/middleware/compress.js // interfaces(`(options) => middleware`) exposed by koa-compress match the framework middleware requirements -module.exports = require('koa-compress'); +module.exports = require("koa-compress"); ``` ```js // config/config.default.js module.exports = { - middleware: ['compress'], + middleware: ["compress"], compress: { threshold: 2048, }, @@ -189,7 +189,7 @@ module.exports = { }; // app/middleware/webpack.js -const webpackMiddleware = require('some-koa-middleware'); +const webpackMiddleware = require("some-koa-middleware"); module.exports = (options, app) => { return webpackMiddleware(options.compiler, options.others); @@ -225,7 +225,7 @@ If we want gzip to be used only by url requests starting with `/static`, the mat ```js module.exports = { gzip: { - match: '/static', + match: "/static", }, }; ``` @@ -242,7 +242,7 @@ module.exports = { match(ctx) { // enabled on ios devices const reg = /iphone|ipad|ipod/i; - return reg.test(ctx.get('user-agent')); + return reg.test(ctx.get("user-agent")); }, }, }; diff --git a/site/docs/basics/middleware.zh-CN.md b/site/docs/basics/middleware.zh-CN.md index ac53170237..6300f7e258 100644 --- a/site/docs/basics/middleware.zh-CN.md +++ b/site/docs/basics/middleware.zh-CN.md @@ -13,8 +13,8 @@ order: 5 ```js // app/middleware/gzip.js -const isJSON = require('koa-is-json'); -const zlib = require('zlib'); +const isJSON = require("koa-is-json"); +const zlib = require("zlib"); async function gzip(ctx, next) { await next(); @@ -28,7 +28,7 @@ async function gzip(ctx, next) { const stream = zlib.createGzip(); stream.end(body); ctx.body = stream; - ctx.set('Content-Encoding', 'gzip'); + ctx.set("Content-Encoding", "gzip"); } ``` @@ -45,8 +45,8 @@ async function gzip(ctx, next) { ```js // app/middleware/gzip.js -const isJSON = require('koa-is-json'); -const zlib = require('zlib'); +const isJSON = require("koa-is-json"); +const zlib = require("zlib"); module.exports = (options) => { return async function gzip(ctx, next) { @@ -65,10 +65,11 @@ module.exports = (options) => { const stream = zlib.createGzip(); stream.end(body); ctx.body = stream; - ctx.set('Content-Encoding', 'gzip'); + ctx.set("Content-Encoding", "gzip"); }; }; ``` + ## 使用中间件 中间件编写完成后,我们还需要手动挂载,支持以下方式: @@ -82,12 +83,12 @@ module.exports = (options) => { ```js module.exports = { // 配置需要的中间件,数组顺序即为中间件的加载顺序 - middleware: ['gzip'], + middleware: ["gzip"], // 配置 gzip 中间件的配置 gzip: { - threshold: 1024 // 小于 1k 的响应体不压缩 - } + threshold: 1024, // 小于 1k 的响应体不压缩 + }, }; ``` @@ -99,14 +100,14 @@ module.exports = { ```js // app.js -module.exports = app => { +module.exports = (app) => { // 在中间件最前面统计请求时间 - app.config.coreMiddleware.unshift('report'); + app.config.coreMiddleware.unshift("report"); }; // app/middleware/report.js module.exports = () => { - return async function(ctx, next) { + return async function (ctx, next) { const startTime = Date.now(); await next(); // 上报请求时间 @@ -123,11 +124,12 @@ module.exports = () => { 如果你只想针对单个路由生效,可以直接在 `app/router.js` 中实例化和挂载,如下: ```js -module.exports = app => { +module.exports = (app) => { const gzip = app.middleware.gzip({ threshold: 1024 }); - app.router.get('/needgzip', gzip, app.controller.handler); + app.router.get("/needgzip", gzip, app.controller.handler); }; ``` + ## 框架默认中间件 除了应用层加载中间件之外,框架自身和其他插件也会加载许多中间件。所有这些自带中间件的配置项都可以通过修改配置文件中的同名配置项来进行更改。例如,框架自带的中间件列表中有一个名为 `bodyParser` 的中间件(框架的加载器会将文件名中的分隔符都转换为驼峰形式的变量名)。如果我们想要修改 `bodyParser` 的配置,只需要在 `config/config.default.js` 中编写如下内容: @@ -135,12 +137,13 @@ module.exports = app => { ```js module.exports = { bodyParser: { - jsonLimit: '10mb', + jsonLimit: "10mb", }, }; ``` **注意:框架和插件加载的中间件会在应用层配置的中间件之前被加载。框架默认中间件不能被应用层中间件覆盖。如果应用层有自定义同名中间件,启动时将会报错。** + ## 使用 Koa 的中间件 在框架里面可以非常容易地引入 Koa 中间件生态。 @@ -148,8 +151,8 @@ module.exports = { 以 [`koa-compress`](https://github.com/koajs/compress) 为例,在 Koa 中使用时: ```js -const koa = require('koa'); -const compress = require('koa-compress'); +const koa = require("koa"); +const compress = require("koa-compress"); const app = new koa(); @@ -162,13 +165,13 @@ app.use(compress(options)); ```js // app/middleware/compress.js // koa-compress 暴露的接口(`(options) => middleware`)和框架对中间件要求一致 -module.exports = require('koa-compress'); +module.exports = require("koa-compress"); ``` ```js // config/config.default.js module.exports = { - middleware: ['compress'], + middleware: ["compress"], compress: { threshold: 2048, }, @@ -187,12 +190,13 @@ module.exports = { }; // app/middleware/webpack.js -const webpackMiddleware = require('some-koa-middleware'); +const webpackMiddleware = require("some-koa-middleware"); module.exports = (options, app) => { return webpackMiddleware(options.compiler, options.others); }; ``` + ## 通用配置 无论是应用层加载的中间件还是框架自带中间件,都支持几个通用的配置项: @@ -222,7 +226,7 @@ module.exports = { ```js module.exports = { gzip: { - match: '/static', + match: "/static", }, }; ``` @@ -239,7 +243,7 @@ module.exports = { match(ctx) { // 只有 iOS 设备才开启 const reg = /iphone|ipad|ipod/i; - return reg.test(ctx.get('user-agent')); + return reg.test(ctx.get("user-agent")); }, }, }; diff --git a/site/docs/basics/objects.md b/site/docs/basics/objects.md index 9478c0881e..15db7d7c59 100644 --- a/site/docs/basics/objects.md +++ b/site/docs/basics/objects.md @@ -21,16 +21,16 @@ Framework will emits some events when server running, application developers or // app.js module.exports = (app) => { - app.once('server', (server) => { + app.once("server", (server) => { // websocket }); - app.on('error', (err, ctx) => { + app.on("error", (err, ctx) => { // report error }); - app.on('request', (ctx) => { + app.on("request", (ctx) => { // log receive request }); - app.on('response', (ctx) => { + app.on("response", (ctx) => { // ctx.starttime is set by framework const used = Date.now() - ctx.starttime; // log total cost @@ -174,7 +174,7 @@ In the Controller file, there are two ways to use the Controller base class: // app/controller/user.js // get from egg (recommend) -const Controller = require('egg').Controller; +const Controller = require("egg").Controller; class UserController extends Controller { // implement } @@ -198,7 +198,7 @@ The properties of the Service base class are the same as those of the [Controlle // app/service/user.js // get from egg (recommend) -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { // implement } @@ -249,7 +249,7 @@ In application development, we may often customize some helper methods, such as // app/extend/helper.js module.exports = { formatUser(user) { - return only(user, ['name', 'phone']); + return only(user, ["name", "phone"]); }, }; ``` @@ -300,7 +300,7 @@ Subscription is a common model for subscribing, for example, the consumer in mes The base class of Subscription can be exported in the following way. ```js -const Subscription = require('egg').Subscription; +const Subscription = require("egg").Subscription; class Schedule extends Subscription { // This method should be implemented diff --git a/site/docs/basics/objects.zh-CN.md b/site/docs/basics/objects.zh-CN.md index 5b6ac0a4d7..5ff4fcd0b9 100644 --- a/site/docs/basics/objects.zh-CN.md +++ b/site/docs/basics/objects.zh-CN.md @@ -21,16 +21,16 @@ Application 是全局应用对象。在一个应用中,每个进程只会实 // app.js module.exports = (app) => { - app.once('server', (server) => { + app.once("server", (server) => { // websocket 相关操作 }); - app.on('error', (err, ctx) => { + app.on("error", (err, ctx) => { // 上报错误 }); - app.on('request', (ctx) => { + app.on("request", (ctx) => { // 记录收到的请求 }); - app.on('response', (ctx) => { + app.on("response", (ctx) => { // ctx.starttime 是由框架设置的 const used = Date.now() - ctx.starttime; // 记录请求总耗时 @@ -85,6 +85,7 @@ class UserController extends Controller { } } ``` + ## Context Context 是一个**请求级别的对象**,继承自 [Koa.Context]。在每次收到用户请求时,框架都会实例化一个 Context 对象。这个对象封装了这次用户请求的信息,并提供了许多便捷的方法来获取请求参数或者设置响应信息。框架会将所有的 [Service] 挂载到 Context 实例上。部分插件也会将其他方法和对象挂载至其上(如 [egg-sequelize] 会将所有的 model 挂到 Context 上)。 @@ -131,6 +132,7 @@ exports.task = async (ctx) => { await ctx.service.posts.refresh(); }; ``` + ## Request & Response Request 是一个**请求级别的对象**,继承自 `[Koa.Request]`。封装了 Node.js 原生的 HTTP Request 对象,提供了一系列辅助方法获取 HTTP 请求常用参数。 @@ -157,6 +159,7 @@ class UserController extends Controller { - `[Koa]` 会在 Context 上代理一部分 Request 和 Response 上的方法和属性,参见 `[Koa.Context]`。 - 如上面例子中的 `ctx.request.query.id` 和 `ctx.query.id` 是等价的,`ctx.response.body =` 和 `ctx.body =` 也是等价的。 - 需要注意的是,获取 POST 的 body 应该使用 `ctx.request.body`,而不是 `ctx.body`。 + ## Controller 框架提供了一个 Controller 基类,并推荐所有的 `Controller` 都继承于该基类实现。这个 Controller 基类有下列属性: @@ -173,7 +176,7 @@ class UserController extends Controller { // app/controller/user.js // 从 egg 上获取(推荐) -const Controller = require('egg').Controller; +const Controller = require("egg").Controller; class UserController extends Controller { // 实现 } @@ -186,6 +189,7 @@ module.exports = (app) => { }; }; ``` + ## Service 框架提供了一个 Service 基类,并推荐所有的 Service 都继承于该基类实现。 @@ -196,7 +200,7 @@ Service 基类的属性和 [Controller](#controller) 基类属性一致,访问 // app/service/user.js // 从 egg 上获取(推荐) -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { // implement } @@ -209,6 +213,7 @@ module.exports = (app) => { }; }; ``` + ## Helper Helper 用来提供一些实用的 utility 函数。它的作用在于我们可以将一些常用的动作抽离在 `helper.js` 里面成为一个独立的函数。这样可以利用 JavaScript 编写复杂的逻辑,避免逻辑分散于各个地方,同时便于更好地编写测试用例。 @@ -246,10 +251,11 @@ class UserController extends Controller { // app/extend/helper.js module.exports = { formatUser(user) { - return only(user, ['name', 'phone']); + return only(user, ["name", "phone"]); }, }; ``` + ## Config 我们推荐应用开发遵循配置和代码分离的原则,将一些需要硬编码的业务配置都放到配置文件中。同时,配置文件支持各个不同的运行环境使用不同的配置,使用起来也非常方便。所有框架、插件和应用级别的配置都可以通过 `Config` 对象获取到。关于框架的配置,可以详细阅读[Config 配置](./config.md)章节。 @@ -257,6 +263,7 @@ module.exports = { ### 获取方式 我们可以通过 `app.config` 从 `Application` 实例上获取到 `config` 对象,也可以在 Controller、Service、Helper 的实例上通过 `this.config` 获取到 `config` 对象。 + ## Logger 框架内置了功能强大的[日志功能](../core/logger.md),可以非常方便地打印各种级别的日志到对应的日志文件中,每一个 logger 对象都提供了 4 个级别的方法: @@ -295,7 +302,7 @@ module.exports = { 你可以通过以下方式来引用 `Subscription` 基类: ```js -const Subscription = require('egg').Subscription; +const Subscription = require("egg").Subscription; class Schedule extends Subscription { // 需要实现此方法 @@ -307,6 +314,7 @@ class Schedule extends Subscription { 插件开发者可以根据自己的需求,基于它定制订阅规范,例如定时任务就是使用这种规范实现的。 相关链接: + - [koa](http://koajs.com) - [koa.application](http://koajs.com/#application) - [koa.context](http://koajs.com/#context) diff --git a/site/docs/basics/plugin.md b/site/docs/basics/plugin.md index 2bb91b711f..3432f1bc6e 100644 --- a/site/docs/basics/plugin.md +++ b/site/docs/basics/plugin.md @@ -61,7 +61,7 @@ Then you need to declare it in the `config / plugin.js` application or framework // Use mysql plugin exports.mysql = { enable: true, - package: 'egg-mysql', + package: "egg-mysql", }; ``` @@ -111,7 +111,7 @@ Then declare in `plugin.local.js`: // config / plugin.local.js exports.dev = { enable: true, - package: 'egg-dev', + package: "egg-dev", }; ``` @@ -131,10 +131,10 @@ In this way, `npm i --production` in the production environment does not need to ```js // config / plugin.js -const path = require('path'); +const path = require("path"); exports.mysql = { enable: true, - path: path.join(__dirname, '../lib/plugin/egg-mysql'), + path: path.join(__dirname, "../lib/plugin/egg-mysql"), }; ``` @@ -146,11 +146,11 @@ The plugin will usually contain its own default configuration, you can overwrite // config / config.default.js exports.mysql = { client: { - host: 'mysql.com', - port: '3306', - user: 'test_user', - password: 'test_password', - database: 'test', + host: "mysql.com", + port: "3306", + user: "test_user", + password: "test_password", + database: "test", }, }; ``` diff --git a/site/docs/basics/plugin.zh-CN.md b/site/docs/basics/plugin.zh-CN.md index d2aaa8b67d..513ead1761 100644 --- a/site/docs/basics/plugin.zh-CN.md +++ b/site/docs/basics/plugin.zh-CN.md @@ -11,6 +11,7 @@ order: 9 - 如何编写一个插件? 接下来我们就来逐一讨论。 + ## 为什么要插件 我们在使用 Koa 中间件过程中发现了下面一些问题: @@ -35,6 +36,7 @@ order: 9 - 当遇到上一节提到的场景时,应用需引入插件。 - 插件本身可以包含中间件。 - 多个插件可以包装为一个[上层框架](../advanced/framework.md)。 + ## 使用插件 插件通常通过 npm 模块的方式进行复用: @@ -60,7 +62,7 @@ $ npm i egg-mysql --save // 使用 mysql 插件 exports.mysql = { enable: true, - package: 'egg-mysql', + package: "egg-mysql", }; ``` @@ -110,7 +112,7 @@ exports.onerror = false; // config/plugin.local.js exports.dev = { enable: true, - package: 'egg-dev', + package: "egg-dev", }; ``` @@ -118,7 +120,7 @@ exports.dev = { **注意:** -- `plugin.default.js` 不存在 +- `plugin.default.js` 不存在 - **只能在应用层使用,框架层请勿使用。** ### package 和 path @@ -129,12 +131,13 @@ exports.dev = { ```js // config/plugin.js -const path = require('path'); +const path = require("path"); exports.mysql = { enable: true, - path: path.join(__dirname, '../lib/plugin/egg-mysql'), + path: path.join(__dirname, "../lib/plugin/egg-mysql"), }; ``` + ## 插件配置 插件一般会包含自己的默认配置。应用开发者可以在 `config.default.js` 中覆盖对应的配置: @@ -143,16 +146,17 @@ exports.mysql = { // config/config.default.js exports.mysql = { client: { - host: 'mysql.com', - port: '3306', - user: 'test_user', - password: 'test_password', - database: 'test' - } + host: "mysql.com", + port: "3306", + user: "test_user", + password: "test_password", + database: "test", + }, }; ``` 具体的合并规则可以参见[配置](./config.md)。 + ## 插件列表 - 框架默认内置了企业级应用[常用的插件](https://eggjs.org/zh-cn/plugins/): diff --git a/site/docs/basics/router.md b/site/docs/basics/router.md index 1af5cedaf0..74167c94de 100644 --- a/site/docs/basics/router.md +++ b/site/docs/basics/router.md @@ -15,7 +15,7 @@ By unifying routing rules, we can avoid the routing logics scattered in many pla // app/router.js module.exports = (app) => { const { router, controller } = app; - router.get('/user/:id', controller.user.info); + router.get("/user/:id", controller.user.info); }; ``` @@ -78,11 +78,11 @@ Here are some examples of writing routing rules: // app/router.js module.exports = (app) => { const { router, controller } = app; - router.get('/home', controller.home); - router.get('/user/:id', controller.user.page); - router.post('/admin', isAdmin, controller.admin); - router.post('/user', isLoginUser, hasAdminPermission, controller.user.create); - router.post('/api/v1/comments', controller.v1.comments.create); // app/controller/v1/comments.js + router.get("/home", controller.home); + router.get("/user/:id", controller.user.page); + router.post("/admin", isAdmin, controller.admin); + router.post("/user", isLoginUser, hasAdminPermission, controller.user.create); + router.post("/api/v1/comments", controller.v1.comments.create); // app/controller/v1/comments.js }; ``` @@ -94,8 +94,8 @@ We provide `app.router.resources('routerName', 'pathMatch', 'controller')` to ge // app/router.js module.exports = (app) => { const { router, controller } = app; - router.resources('posts', '/posts', controller.posts); - router.resources('users', '/api/v1/users', controller.v1.users); // app/controller/v1/users.js + router.resources("posts", "/posts", controller.posts); + router.resources("users", "/api/v1/users", controller.v1.users); // app/controller/v1/users.js }; ``` @@ -141,7 +141,7 @@ More practical examples will be shown below to demonstrate how to use the router ```js // app/router.js module.exports = (app) => { - app.router.get('/search', app.controller.search.index); + app.router.get("/search", app.controller.search.index); }; // app/controller/search.js @@ -157,7 +157,7 @@ exports.index = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get('/user/:id/:name', app.controller.user.info); + app.router.get("/user/:id/:name", app.controller.user.info); }; // app/controller/user.js @@ -175,10 +175,7 @@ Regular expressions, as well, can be used in routing rules to acquire parameters ```js // app/router.js module.exports = (app) => { - app.router.get( - /^\/package\/([\w-.]+\/[\w-.]+)$/, - app.controller.package.detail, - ); + app.router.get(/^\/package\/([\w-.]+\/[\w-.]+)$/, app.controller.package.detail); }; // app/controller/package.js @@ -196,7 +193,7 @@ exports.detail = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.post('/form', app.controller.form.post); + app.router.post("/form", app.controller.form.post); }; // app/controller/form.js @@ -231,17 +228,17 @@ exports.security = { ```js // app/router.js module.exports = (app) => { - app.router.post('/user', app.controller.user); + app.router.post("/user", app.controller.user); }; // app/controller/user.js const createRule = { username: { - type: 'email', + type: "email", }, password: { - type: 'password', - compare: 're-password', + type: "password", + compare: "re-password", }, }; @@ -261,13 +258,13 @@ exports.create = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get('index', '/home/index', app.controller.home.index); - app.redirect('/', '/home/index', 302); + app.router.get("index", "/home/index", app.controller.home.index); + app.redirect("/", "/home/index", 302); }; // app/controller/home.js exports.index = async (ctx) => { - ctx.body = 'hello controller'; + ctx.body = "hello controller"; }; // curl -L http://localhost:7001 @@ -278,15 +275,15 @@ exports.index = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get('/search', app.controller.search.index); + app.router.get("/search", app.controller.search.index); }; // app/controller/search.js exports.index = async (ctx) => { const type = ctx.query.type; - const q = ctx.query.q || 'nodejs'; + const q = ctx.query.q || "nodejs"; - if (type === 'bing') { + if (type === "bing") { ctx.redirect(`http://cn.bing.com/search?q=${q}`); } else { ctx.redirect(`https://www.google.co.kr/search?q=${q}`); @@ -318,12 +315,7 @@ module.exports = () => { // app/router.js module.exports = (app) => { - app.router.get( - 's', - '/search', - app.middleware.uppercase(), - app.controller.search, - ); + app.router.get("s", "/search", app.middleware.uppercase(), app.controller.search); }; // curl http://localhost:7001/search?name=egg @@ -338,20 +330,20 @@ If there is a need for some reasons, you can split routing rules like below: ```js // app/router.js module.exports = (app) => { - require('./router/news')(app); - require('./router/admin')(app); + require("./router/news")(app); + require("./router/admin")(app); }; // app/router/news.js module.exports = (app) => { - app.router.get('/news/list', app.controller.news.list); - app.router.get('/news/detail', app.controller.news.detail); + app.router.get("/news/list", app.controller.news.list); + app.router.get("/news/detail", app.controller.news.detail); }; // app/router/admin.js module.exports = (app) => { - app.router.get('/admin/user', app.controller.admin.user); - app.router.get('/admin/log', app.controller.admin.log); + app.router.get("/admin/user", app.controller.admin.user); + app.router.get("/admin/log", app.controller.admin.log); }; ``` diff --git a/site/docs/basics/router.zh-CN.md b/site/docs/basics/router.zh-CN.md index 7f8101a330..02bb37f54b 100644 --- a/site/docs/basics/router.zh-CN.md +++ b/site/docs/basics/router.zh-CN.md @@ -6,6 +6,7 @@ order: 6 Router 主要用来描述请求 URL 和具体承担执行动作的 Controller 的对应关系,框架约定了 `app/router.js` 文件用于统一所有路由规则。 通过统一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突。集中在一起,我们可以更方便地来查看全局的路由规则。 + ## 如何定义 Router - `app/router.js` 里面定义 URL 路由规则 @@ -14,7 +15,7 @@ Router 主要用来描述请求 URL 和具体承担执行动作的 Controller // app/router.js module.exports = (app) => { const { router, controller } = app; - router.get('/user/:id', controller.user.info); + router.get("/user/:id", controller.user.info); }; ``` @@ -33,6 +34,7 @@ class UserController extends Controller { ``` 这样就完成了一个最简单的 Router 定义,当用户执行 `GET /user/123`,`user.js` 这个里面的 info 方法就会执行。 + ## Router 详细定义说明 下面是路由的完整定义,参数可以根据场景的不同,自由选择: @@ -74,13 +76,13 @@ router.verb('router-name', 'path-match', middleware1, ..., middlewareN, app.cont ```js // app/router.js -module.exports = app => { +module.exports = (app) => { const { router, controller } = app; - router.get('/home', controller.home); - router.get('/user/:id', controller.user.page); - router.post('/admin', isAdmin, controller.admin); - router.post('/user', isLoginUser, hasAdminPermission, controller.user.create); - router.post('/api/v1/comments', controller.v1.comments.create); // app/controller/v1/comments.js + router.get("/home", controller.home); + router.get("/user/:id", controller.user.page); + router.post("/admin", isAdmin, controller.admin); + router.post("/user", isLoginUser, hasAdminPermission, controller.user.create); + router.post("/api/v1/comments", controller.v1.comments.create); // app/controller/v1/comments.js }; ``` @@ -90,10 +92,10 @@ module.exports = app => { ```js // app/router.js -module.exports = app => { +module.exports = (app) => { const { router, controller } = app; - router.resources('posts', '/api/posts', controller.posts); - router.resources('users', '/api/v1/users', controller.v1.users); // app/controller/v1/users.js + router.resources("posts", "/api/posts", controller.posts); + router.resources("users", "/api/v1/users", controller.v1.users); // app/controller/v1/users.js }; ``` @@ -127,6 +129,7 @@ exports.destroy = async () => {}; ``` 如果我们不需要其中的某些方法,可以省略在 `posts.js` 里面的实现,这样对应的 URL 路径也不会注册到 Router 中。 + ## router 实战 下面通过更多实际的例子,来说明 `router` 的用法。 @@ -138,7 +141,7 @@ exports.destroy = async () => {}; ```js // app/router.js module.exports = (app) => { - app.router.get('/search', app.controller.search.index); + app.router.get("/search", app.controller.search.index); }; // app/controller/search.js @@ -154,7 +157,7 @@ exports.index = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get('/user/:id/:name', app.controller.user.info); + app.router.get("/user/:id/:name", app.controller.user.info); }; // app/controller/user.js @@ -172,10 +175,7 @@ exports.info = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get( - /^\/package\/([\w-.]+\/[\w-.]+)$/, - app.controller.package.detail, - ); + app.router.get(/^\/package\/([\w-.]+\/[\w-.]+)$/, app.controller.package.detail); }; // app/controller/package.js @@ -193,7 +193,7 @@ exports.detail = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.post('/form', app.controller.form.post); + app.router.post("/form", app.controller.form.post); }; // app/controller/form.js @@ -217,7 +217,7 @@ exports.post = async (ctx) => { ```javascript exports.security = { - csrf: false + csrf: false, }; ``` @@ -226,17 +226,17 @@ exports.security = { ```js // app/router.js module.exports = (app) => { - app.router.post('/user', app.controller.user); + app.router.post("/user", app.controller.user); }; // app/controller/user.js const createRule = { username: { - type: 'email', + type: "email", }, password: { - type: 'password', - compare: 're-password', + type: "password", + compare: "re-password", }, }; @@ -256,13 +256,13 @@ exports.create = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get('index', '/home/index', app.controller.home.index); - app.router.redirect('/', '/home/index', 302); + app.router.get("index", "/home/index", app.controller.home.index); + app.router.redirect("/", "/home/index", 302); }; // app/controller/home.js exports.index = async (ctx) => { - ctx.body = 'hello controller'; + ctx.body = "hello controller"; }; // curl -L http://localhost:7001 @@ -273,15 +273,15 @@ exports.index = async (ctx) => { ```js // app/router.js module.exports = (app) => { - app.router.get('/search', app.controller.search.index); + app.router.get("/search", app.controller.search.index); }; // app/controller/search.js exports.index = async (ctx) => { const type = ctx.query.type; - const q = ctx.query.q || 'nodejs'; + const q = ctx.query.q || "nodejs"; - if (type === 'bing') { + if (type === "bing") { ctx.redirect(`http://cn.bing.com/search?q=${q}`); } else { ctx.redirect(`https://www.google.co.kr/search?q=${q}`); @@ -313,12 +313,7 @@ module.exports = () => { // app/router.js module.exports = (app) => { - app.router.get( - 's', - '/search', - app.middleware.uppercase(), - app.controller.search.index, - ); + app.router.get("s", "/search", app.middleware.uppercase(), app.controller.search.index); }; // curl http://localhost:7001/search?name=egg @@ -333,20 +328,20 @@ module.exports = (app) => { ```js // app/router.js module.exports = (app) => { - require('./router/news')(app); - require('./router/admin')(app); + require("./router/news")(app); + require("./router/admin")(app); }; // app/router/news.js module.exports = (app) => { - app.router.get('/news/list', app.controller.news.list); - app.router.get('/news/detail', app.controller.news.detail); + app.router.get("/news/list", app.controller.news.list); + app.router.get("/news/detail", app.controller.news.detail); }; // app/router/admin.js module.exports = (app) => { - app.router.get('/admin/user', app.controller.admin.user); - app.router.get('/admin/log', app.controller.admin.log); + app.router.get("/admin/user", app.controller.admin.user); + app.router.get("/admin/log", app.controller.admin.log); }; ``` diff --git a/site/docs/basics/schedule.md b/site/docs/basics/schedule.md index 734f72bf9c..fd3095e415 100644 --- a/site/docs/basics/schedule.md +++ b/site/docs/basics/schedule.md @@ -18,21 +18,21 @@ All scheduled tasks should be placed in directory `app/schedule`. Each file is a A simple example, to define a scheduled task to update the remote data to the memory cache, we can create a `update_cache.js` file in the directory 'app/schedule` ```js -const Subscription = require('egg').Subscription; +const Subscription = require("egg").Subscription; class UpdateCache extends Subscription { // using `schedule` property to set the scheduled task execution interval and other configurations static get schedule() { return { - interval: '1m', // 1 minute interval - type: 'all', // specify all `workers` need to execute + interval: "1m", // 1 minute interval + type: "all", // specify all `workers` need to execute }; } // `subscribe` is the function to be executed when the scheduled task is triggered async subscribe() { - const res = await this.ctx.curl('http://www.api.com/cache', { - dataType: 'json', + const res = await this.ctx.curl("http://www.api.com/cache", { + dataType: "json", }); this.ctx.app.cache = res.data; } @@ -46,12 +46,12 @@ Can also be abbreviated as ```js module.exports = { schedule: { - interval: '1m', // 1 minute interval - type: 'all', // specify all `workers` need to execute + interval: "1m", // 1 minute interval + type: "all", // specify all `workers` need to execute }, async task(ctx) { - const res = await ctx.curl('http://www.api.com/cache', { - dataType: 'json', + const res = await ctx.curl("http://www.api.com/cache", { + dataType: "json", }); ctx.app.cache = res.data; }, @@ -80,7 +80,7 @@ Configure the scheduled tasks by `schedule.interval`, scheduled tasks will be ex module.exports = { schedule: { // executed every 10 seconds - interval: '10s', + interval: "10s", }, }; ``` @@ -107,7 +107,7 @@ Configure the scheduled tasks by `schedule.cron`, scheduled tasks will be execut module.exports = { schedule: { // executed every three hours (zero minutes and zero seconds) - cron: '0 0 */3 * * *', + cron: "0 0 */3 * * *", }, }; ``` @@ -151,11 +151,11 @@ module.exports = (app) => { return { schedule: { interval: app.config.cacheTick, - type: 'all', + type: "all", }, async task(ctx) { - const res = await ctx.curl('http://www.api.com/cache', { - contentType: 'json', + const res = await ctx.curl("http://www.api.com/cache", { + contentType: "json", }); ctx.app.cache = res.data; }, @@ -172,13 +172,13 @@ There are some scenarios we may need to manually execute scheduled tasks, for ex - Executing scheduled tasks manually for more elegant unit testing of scheduled tasks. ```js -const mm = require('egg-mock'); -const assert = require('assert'); +const mm = require("egg-mock"); +const assert = require("assert"); -it('should schedule work fine', async () => { +it("should schedule work fine", async () => { const app = mm.app(); await app.ready(); - await app.runSchedule('update_cache'); + await app.runSchedule("update_cache"); assert(app.cache); }); ``` @@ -190,7 +190,7 @@ module.exports = (app) => { app.beforeStart(async () => { // ensure the data is ready before the application starts listening port // follow-up data updates automatically by the scheduled task - await app.runSchedule('update_cache'); + await app.runSchedule("update_cache"); }); }; ``` @@ -212,7 +212,7 @@ module.exports = (agent) => { agent.mq.subscribe(this.schedule.scene, () => this.sendOne()); } } - agent.schedule.use('cluster', ClusterStrategy); + agent.schedule.use("cluster", ClusterStrategy); }; ``` diff --git a/site/docs/basics/schedule.zh-CN.md b/site/docs/basics/schedule.zh-CN.md index 40f9946bd1..a0b7391567 100644 --- a/site/docs/basics/schedule.zh-CN.md +++ b/site/docs/basics/schedule.zh-CN.md @@ -10,6 +10,7 @@ order: 10 3. 定时进行文件切割、临时文件删除。 框架提供了一套机制来让定时任务的编写和维护更加优雅。 + ## 编写定时任务 所有的定时任务都统一存放在 `app/schedule` 目录下,每一个文件都是一个独立的定时任务,可以配置定时任务的属性和要执行的方法。 @@ -17,21 +18,21 @@ order: 10 一个简单的例子,我们定义一个更新远程数据到内存缓存的定时任务,就可以在 `app/schedule` 目录下创建一个 `update_cache.js` 文件。 ```js -const Subscription = require('egg').Subscription; +const Subscription = require("egg").Subscription; class UpdateCache extends Subscription { // 通过 schedule 属性来设置定时任务的执行间隔等配置 static get schedule() { return { - interval: '1m', // 1 分钟间隔 - type: 'all', // 指定所有的 worker 都需要执行 + interval: "1m", // 1 分钟间隔 + type: "all", // 指定所有的 worker 都需要执行 }; } // subscribe 是真正定时任务执行时被运行的函数 async subscribe() { - const res = await this.ctx.curl('http://www.api.com/cache', { - dataType: 'json', + const res = await this.ctx.curl("http://www.api.com/cache", { + dataType: "json", }); this.ctx.app.cache = res.data; } @@ -45,12 +46,12 @@ module.exports = UpdateCache; ```js module.exports = { schedule: { - interval: '1m', // 1 分钟间隔 - type: 'all', // 指定所有的 worker 都需要执行 + interval: "1m", // 1 分钟间隔 + type: "all", // 指定所有的 worker 都需要执行 }, async task(ctx) { - const res = await ctx.curl('http://www.api.com/cache', { - dataType: 'json', + const res = await ctx.curl("http://www.api.com/cache", { + dataType: "json", }); ctx.app.cache = res.data; }, @@ -79,7 +80,7 @@ module.exports = { module.exports = { schedule: { // 每 10 秒执行一次 - interval: '10s', + interval: "10s", }, }; ``` @@ -106,7 +107,7 @@ module.exports = { module.exports = { schedule: { // 每三小时准点执行一次 - cron: '0 0 */3 * * *', + cron: "0 0 */3 * * *", }, }; ``` @@ -140,6 +141,7 @@ config.customLogger = { }, }; ``` + ### 动态配置定时任务 有时候,我们需要配置定时任务的参数。定时任务还可以支持另一种写法: @@ -149,11 +151,11 @@ module.exports = (app) => { return { schedule: { interval: app.config.cacheTick, - type: 'all', + type: "all", }, async task(ctx) { - const res = await ctx.curl('http://www.api.com/cache', { - contentType: 'json', + const res = await ctx.curl("http://www.api.com/cache", { + contentType: "json", }); ctx.app.cache = res.data; }, @@ -170,13 +172,13 @@ module.exports = (app) => { - 手动执行定时任务可以更优雅地编写定时任务的单元测试。 ```js -const mm = require('egg-mock'); -const assert = require('assert'); +const mm = require("egg-mock"); +const assert = require("assert"); -it('should schedule work fine', async () => { +it("should schedule work fine", async () => { const app = mm.app(); await app.ready(); - await app.runSchedule('update_cache'); + await app.runSchedule("update_cache"); assert(app.cache); }); ``` @@ -188,7 +190,7 @@ module.exports = (app) => { app.beforeStart(async () => { // 保证应用启动监听端口前,数据已经准备好 // 后续数据的更新由定时任务自动触发 - await app.runSchedule('update_cache'); + await app.runSchedule("update_cache"); }); }; ``` @@ -210,7 +212,7 @@ module.exports = (agent) => { agent.mq.subscribe(this.schedule.scene, () => this.sendOne()); } } - agent.schedule.use('cluster', ClusterStrategy); + agent.schedule.use("cluster", ClusterStrategy); }; ``` @@ -218,4 +220,4 @@ module.exports = (agent) => { - `this.schedule` - 定时任务的属性,所有任务默认支持的 `disable` 属性,以及其他自定义配置的解析。 - `this.sendOne(...args)` - 随机通知某个 worker 执行 task,`args` 会传递给 `subscribe(...args)` 或 `task(ctx, ...args)` 方法。 -- `this.sendAll(...args)` - 通知所有的 worker 执行 task。 \ No newline at end of file +- `this.sendAll(...args)` - 通知所有的 worker 执行 task。 diff --git a/site/docs/basics/service.md b/site/docs/basics/service.md index 3a8e3af6f2..c4cd7cf4c0 100644 --- a/site/docs/basics/service.md +++ b/site/docs/basics/service.md @@ -18,14 +18,11 @@ Simply speaking, Service is an abstract layer which is used to encapsulate busin ```js // app/service/user.js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { async find(uid) { - const user = await this.ctx.db.query( - 'select * from user where uid = ?', - uid, - ); + const user = await this.ctx.db.query("select * from user where uid = ?", uid); return user; } } @@ -73,11 +70,11 @@ We begin to see how to use Service from a complete example below. ```js // app/router.js module.exports = (app) => { - app.router.get('/user/:id', app.controller.user.info); + app.router.get("/user/:id", app.controller.user.info); }; // app/controller/user.js -const Controller = require('egg').Controller; +const Controller = require("egg").Controller; class UserController extends Controller { async info() { const { ctx } = this; @@ -89,7 +86,7 @@ class UserController extends Controller { module.exports = UserController; // app/service/user.js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { // the constructor is not a must by default // constructor(ctx) { @@ -99,10 +96,7 @@ class UserService extends Service { // } async find(uid) { // suppose we've got user's id and are going to get detailed user information from databases - const user = await this.ctx.db.query( - 'select * from user where uid = ?', - uid, - ); + const user = await this.ctx.db.query("select * from user where uid = ?", uid); // suppose some complex processes should be made here, and demanded informations are returned then. const picture = await this.getPicture(uid); @@ -116,7 +110,7 @@ class UserService extends Service { async getPicture(uid) { const result = await this.ctx.curl(`http://photoserver/uid=${uid}`, { - dataType: 'json', + dataType: "json", }); return result.data; } diff --git a/site/docs/basics/service.zh-CN.md b/site/docs/basics/service.zh-CN.md index 330852ddc7..ab77a21e2a 100644 --- a/site/docs/basics/service.zh-CN.md +++ b/site/docs/basics/service.zh-CN.md @@ -8,22 +8,21 @@ order: 8 - 保持 Controller 中的逻辑更简洁。 - 保持业务逻辑的独立性,抽象出的 Service 可以被多个 Controller 重复使用。 - 分离逻辑和展示,这样更便于编写测试用例。具体的测试用例编写方法,可以参见[这里](../core/unittest.md)。 + ## 使用场景 - 数据处理:当需要展示的信息须从数据库获取,并经规则计算后才能显示给用户,或计算后需更新数据库时。 - 第三方服务调用:例如获取 GitHub 信息等。 + ## 定义 Service ```js // app/service/user.js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { async find(uid) { - const user = await this.ctx.db.query( - 'select * from user where uid = ?', - uid - ); + const user = await this.ctx.db.query("select * from user where uid = ?", uid); return user; } } @@ -65,14 +64,15 @@ module.exports = UserService; - 一个 Service 文件仅包含一个类,该类需通过 `module.exports` 导出。 - Service 应通过 Class 形式定义,且继承自 `egg.Service`。 - Service 不是单例,它是请求级别的对象。框架在每次请求中初次访问 `ctx.service.xx` 时才进行实例化。因此,Service 中可以通过 `this.ctx` 获取当前请求的上下文。 + ```js // app/router.js -module.exports = app => { - app.router.get('/user/:id', app.controller.user.info); +module.exports = (app) => { + app.router.get("/user/:id", app.controller.user.info); }; // app/controller/user.js -const Controller = require('egg').Controller; +const Controller = require("egg").Controller; class UserController extends Controller { async info() { const { ctx } = this; @@ -84,7 +84,7 @@ class UserController extends Controller { module.exports = UserController; // app/service/user.js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { // 默认不需要提供构造函数。 /* constructor(ctx) { @@ -94,10 +94,7 @@ class UserService extends Service { } */ async find(uid) { // 假如我们拿到用户 id,从数据库获取用户详细信息 - const user = await this.ctx.db.query( - 'select * from user where uid = ?', - uid - ); + const user = await this.ctx.db.query("select * from user where uid = ?", uid); // 假定这里还有一些复杂的计算,然后返回需要的信息 const picture = await this.getPicture(uid); @@ -105,13 +102,13 @@ class UserService extends Service { return { name: user.user_name, age: user.age, - picture + picture, }; } async getPicture(uid) { const result = await this.ctx.curl(`http://photoserver/uid=${uid}`, { - dataType: 'json' + dataType: "json", }); return result.data; } diff --git a/site/docs/basics/structure.zh-CN.md b/site/docs/basics/structure.zh-CN.md index 884426b154..780fca55d1 100644 --- a/site/docs/basics/structure.zh-CN.md +++ b/site/docs/basics/structure.zh-CN.md @@ -58,7 +58,6 @@ egg-project - `test/**` 用于单元测试,具体参见 [单元测试](../core/unittest.md)。 - `app.js` 和 `agent.js` 用于自定义启动时的初始化工作,具体参见 [启动自定义](./app-start.md)。关于 `agent.js` 的作用,参见 [Agent 机制](../core/cluster-and-ipc.md#agent-机制)。 - 由内置插件约定的目录: - `app/public/**` 用于放置静态资源,具体参见内置插件 [egg-static](https://github.com/eggjs/egg-static)。 diff --git a/site/docs/community/CONTRIBUTING.zh-CN.md b/site/docs/community/CONTRIBUTING.zh-CN.md index e3b7a83500..e367114ca0 100644 --- a/site/docs/community/CONTRIBUTING.zh-CN.md +++ b/site/docs/community/CONTRIBUTING.zh-CN.md @@ -1,7 +1,5 @@ --- - title: 代码贡献规范 - --- 有任何疑问,欢迎提交 [issue](https://github.com/eggjs/egg/issues),或者直接修改提交 [PR](https://github.com/eggjs/egg/pulls)! @@ -54,6 +52,7 @@ $ git checkout -b branch-name # 开发完成后跑下测试是否通过,必要时需要新增或修改测试用例 $ npm test ``` + # 测试通过后,提交代码,message 见下面的规范 ``` @@ -63,6 +62,7 @@ $ git push origin branch-name ``` 由于谁也无法保证过了多久之后还记得多少,为了后期回溯历史的方便,请在提交 MR 时确保提供了以下信息。 + 1. 需求点(一般关联 issue 或者注释都算) 2. 升级原因(不同于 issue,可以简要描述下为什么要处理) 3. 框架测试点(可以关联到测试文件,不用详细描述,关键点即可) @@ -115,7 +115,7 @@ $ git push origin branch-name - **当有非兼容修改(Breaking Change)时必须在这里描述清楚** - 关联相关 issue,如 `Closes #1, Closes #2, #3` -- 如果功能点有新增或修改的,还需要关联文档 `doc` 和 `egg-core` 的 PR,如 `eggjs/egg-core#123` +- 如果功能点有新增或修改的,还需要关联文档 `doc` 和 `egg-core` 的 PR,如 `eggjs/egg-core#123` 示例 @@ -149,6 +149,7 @@ BREAKING CHANGE: - 如果标题被当做一个完整的英语句子,请按照英语句子的语法格式大小写(例如:常见问题 FAQ 中每一个标题都是一个英语句子)。 有关详情,可以参考[英语标题大小写]。 + ## 发布管理 Egg 基于 [semver](语义化版本号)进行发布。 @@ -163,7 +164,7 @@ Egg 基于 [semver](语义化版本号)进行发布。 - `next` 分支设置 tag 为 `next`。上层框架可以通过 `egg@next` 引用开发中的版本进行测试。 - Egg 持续维护的版本以 Milestone 为准。只要是开着的版本,都会进行修复。 -### 发布策略 +### 发布策略 每个大版本都有一个发布经理(PM)负责管理。他/她的工作内容包括: @@ -196,10 +197,10 @@ Egg 基于 [semver](语义化版本号)进行发布。 } ``` -[semver]: https://semver.org/lang/zh-CN/ -[Release Proposal MR]: https://github.com/nodejs/node/pull/4181 -[Node CHANGELOG]: https://github.com/nodejs/node/blob/master/CHANGELOG.md -[1.x Milestone]: https://github.com/eggjs/egg/milestone/1 -[npm]: http://npmjs.com/ -[我是如何发布一个 npm 包的]: https://fengmk2.com/blog/2016/how-i-publish-a-npm-package -[英语标题大小写]: https://headlinecapitalization.com/ \ No newline at end of file +[semver]: https://semver.org/lang/zh-CN/ +[Release Proposal MR]: https://github.com/nodejs/node/pull/4181 +[Node CHANGELOG]: https://github.com/nodejs/node/blob/master/CHANGELOG.md +[1.x Milestone]: https://github.com/eggjs/egg/milestone/1 +[npm]: http://npmjs.com/ +[我是如何发布一个 npm 包的]: https://fengmk2.com/blog/2016/how-i-publish-a-npm-package +[英语标题大小写]: https://headlinecapitalization.com/ diff --git a/site/docs/community/faq.md b/site/docs/community/faq.md index 02ac70500d..874546b2af 100644 --- a/site/docs/community/faq.md +++ b/site/docs/community/faq.md @@ -27,10 +27,10 @@ Please make sure you don't make a mistake like the code below: ```js // config/config.default.js -exports.someKeys = 'abc'; +exports.someKeys = "abc"; module.exports = (appInfo) => { const config = {}; - config.keys = '123456'; + config.keys = "123456"; return config; }; ``` @@ -55,9 +55,9 @@ Firstly, put a start file in the root directory of your project: ```js // server.js -const egg = require('egg'); +const egg = require("egg"); -const workers = Number(process.argv[2] || require('os').cpus().length); +const workers = Number(process.argv[2] || require("os").cpus().length); egg.startCluster({ workers, baseDir: __dirname, diff --git a/site/docs/community/faq.zh-CN.md b/site/docs/community/faq.zh-CN.md index 199122f1af..ac5afb851d 100644 --- a/site/docs/community/faq.zh-CN.md +++ b/site/docs/community/faq.zh-CN.md @@ -29,10 +29,10 @@ PS:请确保没有写出以下代码: ```js // config/config.default.js -exports.someKeys = 'abc'; +exports.someKeys = "abc"; module.exports = (appInfo) => { const config = {}; - config.keys = '123456'; + config.keys = "123456"; return config; }; ``` @@ -57,9 +57,9 @@ module.exports = (appInfo) => { ```js // server.js -const egg = require('egg'); +const egg = require("egg"); -const workers = Number(process.argv[2] || require('os').cpus().length); +const workers = Number(process.argv[2] || require("os").cpus().length); egg.startCluster({ workers, baseDir: __dirname, @@ -89,6 +89,6 @@ worker 进程没有自动重启的情形通常发生在使用 Jetbrains 旗下 Jetbrains [Safe Write 文档](https://www.jetbrains.com/help/webstorm/2016.3/system-settings.html) 中有提到(翻译如下): ->“如果此复选框打钩,变更的文件将首先被存储在一个临时文件中。如果文件保存成功,则临时文件会替换原文件(从技术上讲,原文件被删除,临时文件被重命名)。” +> “如果此复选框打钩,变更的文件将首先被存储在一个临时文件中。如果文件保存成功,则临时文件会替换原文件(从技术上讲,原文件被删除,临时文件被重命名)。” 由于使用了重命名,文件监听失效。解决方法是关闭 Safe Write 选项。(Settings | Appearance & Behavior | System Settings | Use "safe write",路径可能因版本不同有所差异) diff --git a/site/docs/community/style-guide.md b/site/docs/community/style-guide.md index 6bba90db3d..4e1aa160bd 100644 --- a/site/docs/community/style-guide.md +++ b/site/docs/community/style-guide.md @@ -12,7 +12,7 @@ Old Style: module.exports = (app) => { class UserService extends app.Service { async list() { - return await this.ctx.curl('https://eggjs.org'); + return await this.ctx.curl("https://eggjs.org"); } } return UserService; @@ -22,10 +22,10 @@ module.exports = (app) => { change to: ```js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { async list() { - return await this.ctx.curl('https://eggjs.org'); + return await this.ctx.curl("https://eggjs.org"); } } module.exports = UserService; @@ -34,7 +34,7 @@ module.exports = UserService; Additionally, the `framework developer` needs to change the syntax as follows, otherwise the `application developer` will have problems customizing base classes such as Service: ```js -const egg = require('egg'); +const egg = require("egg"); module.exports = Object.assign(egg, { Application: class MyApplication extends egg.Application { @@ -52,8 +52,8 @@ module.exports = Object.assign(egg, { ```js // app/extend/application.js -const CACHE = Symbol('Application#cache'); -const CacheManager = require('../../lib/cache_manager'); +const CACHE = Symbol("Application#cache"); +const CacheManager = require("../../lib/cache_manager"); module.exports = { get cache() { diff --git a/site/docs/community/style-guide.zh-CN.md b/site/docs/community/style-guide.zh-CN.md index ba168aa0c9..df64589491 100644 --- a/site/docs/community/style-guide.zh-CN.md +++ b/site/docs/community/style-guide.zh-CN.md @@ -12,7 +12,7 @@ title: 代码风格指南 module.exports = (app) => { class UserService extends app.Service { async list() { - return await this.ctx.curl('https://eggjs.org'); + return await this.ctx.curl("https://eggjs.org"); } } return UserService; @@ -22,10 +22,10 @@ module.exports = (app) => { 修改为: ```js -const Service = require('egg').Service; +const Service = require("egg").Service; class UserService extends Service { async list() { - return await this.ctx.curl('https://eggjs.org'); + return await this.ctx.curl("https://eggjs.org"); } } module.exports = UserService; @@ -34,7 +34,7 @@ module.exports = UserService; 同时,框架开发者需要改变写法如下,否则应用开发者自定义 Service 等基类会有问题: ```js -const egg = require('egg'); +const egg = require("egg"); module.exports = Object.assign(egg, { Application: class MyApplication extends egg.Application { @@ -52,8 +52,8 @@ module.exports = Object.assign(egg, { ```js // app/extend/application.js -const CACHE = Symbol('Application#cache'); -const CacheManager = require('../../lib/cache_manager'); +const CACHE = Symbol("Application#cache"); +const CacheManager = require("../../lib/cache_manager"); module.exports = { get cache() { diff --git a/site/docs/core/cluster-and-ipc.md b/site/docs/core/cluster-and-ipc.md index 0558ab611f..fd38052e81 100644 --- a/site/docs/core/cluster-and-ipc.md +++ b/site/docs/core/cluster-and-ipc.md @@ -28,9 +28,9 @@ of which: - usually the number of Worker processes depends on the CPU core number, only in this way can we take full advantage of multi-core resources. ```js -const cluster = require('cluster'); -const http = require('http'); -const numCPUs = require('os').cpus().length; +const cluster = require("cluster"); +const http = require("http"); +const numCPUs = require("os").cpus().length; if (cluster.isMaster) { // Fork workers. @@ -38,8 +38,8 @@ if (cluster.isMaster) { cluster.fork(); } - cluster.on('exit', function (worker, code, signal) { - console.log('worker ' + worker.process.pid + ' died'); + cluster.on("exit", function (worker, code, signal) { + console.log("worker " + worker.process.pid + " died"); }); } else { // Workers can share any TCP connection @@ -47,7 +47,7 @@ if (cluster.isMaster) { http .createServer(function (req, res) { res.writeHead(200); - res.end('hello world\n'); + res.end("hello world\n"); }) .listen(8000); } @@ -179,7 +179,7 @@ module.exports = agent => { ```js // app.js module.exports = (app) => { - app.messenger.on('xxx_action', (data) => { + app.messenger.on("xxx_action", (data) => { // ... }); }; @@ -224,17 +224,17 @@ Worker runs business codes, which are more complicated than those of Agent and M Although every Worker process runs individually, it's necessary for them to communicate with each other which is called inter-process communication(IPC). Below is an example code provided by Node.js officially. ```js -'use strict'; -const cluster = require('cluster'); +"use strict"; +const cluster = require("cluster"); if (cluster.isMaster) { const worker = cluster.fork(); - worker.send('hi there'); - worker.on('message', (msg) => { + worker.send("hi there"); + worker.on("message", (msg) => { console.log(`msg: ${msg} from worker#${worker.id}`); }); } else if (cluster.isWorker) { - process.on('message', (msg) => { + process.on("message", (msg) => { process.send(msg); }); } @@ -290,9 +290,9 @@ To simplify the invocation, we have encapsulated a messenger object and attached // app.js module.exports = (app) => { // Note, only after egg-ready event occurs can the message be sent - app.messenger.once('egg-ready', () => { - app.messenger.sendToAgent('agent-event', { foo: 'bar' }); - app.messenger.sendToApp('app-event', { foo: 'bar' }); + app.messenger.once("egg-ready", () => { + app.messenger.sendToAgent("agent-event", { foo: "bar" }); + app.messenger.sendToApp("app-event", { foo: "bar" }); }); }; ``` @@ -348,14 +348,14 @@ class SourceService extends Service { async checkUpdate() { // check if remote data source has changed const updated = await mockCheck(); - this.ctx.logger.info('check update response %s', updated); + this.ctx.logger.info("check update response %s", updated); return updated; } async update() { // update memory cache from remote memoryCache = await mockFetch(); - this.ctx.logger.info('update memory cache from remote: %j', memoryCache); + this.ctx.logger.info("update memory cache from remote: %j", memoryCache); } } ``` @@ -365,13 +365,13 @@ Write the scheduled task to implement solution one: gets data changes from the r ```js // app/schedule/force_refresh.js exports.schedule = { - interval: '10m', - type: 'all', // run in all workers + interval: "10m", + type: "all", // run in all workers }; exports.task = async (ctx) => { await ctx.service.source.update(); - ctx.app.lastUpdateBy = 'force'; + ctx.app.lastUpdateBy = "force"; }; ``` @@ -380,8 +380,8 @@ Write a scheduled task again to implement check logics of solution two: make a w ```js // app/schedule/pull_refresh.js exports.schedule = { - interval: '10s', - type: 'worker', // only run in one worker + interval: "10s", + type: "worker", // only run in one worker }; exports.task = async (ctx) => { @@ -389,7 +389,7 @@ exports.task = async (ctx) => { if (!needRefresh) return; // notify all workers to update memory cache from `file` - ctx.app.messenger.sendToApp('refresh', 'pull'); + ctx.app.messenger.sendToApp("refresh", "pull"); }; ``` @@ -398,8 +398,8 @@ Listen on the `pullRefresh` event in the customized start-up file and update dat ```js // app.js module.exports = (app) => { - app.messenger.on('refresh', (by) => { - app.logger.info('start update by %s', by); + app.messenger.on("refresh", (by) => { + app.logger.info("start update by %s", by); // create an anonymous context to access service const ctx = app.createAnonymousContext(); ctx.runInBackground(async () => { @@ -415,12 +415,12 @@ Now let's consider how to implement solution three. We need a message-oriented m ```js // agent.js -const Subscriber = require('./lib/subscriber'); +const Subscriber = require("./lib/subscriber"); module.exports = (agent) => { const subscriber = new Subscriber(); // listen changed event, broadcast to all workers - subscriber.on('changed', () => agent.messenger.sendToApp('refresh', 'push')); + subscriber.on("changed", () => agent.messenger.sendToApp("refresh", "push")); }; ``` diff --git a/site/docs/core/cluster-and-ipc.zh-CN.md b/site/docs/core/cluster-and-ipc.zh-CN.md index 602aa23a19..00c2853d0f 100644 --- a/site/docs/core/cluster-and-ipc.zh-CN.md +++ b/site/docs/core/cluster-and-ipc.zh-CN.md @@ -28,9 +28,9 @@ Node.js 官方提供的解决方案是 [Cluster 模块](https://nodejs.org/api/c - Worker 进程的数量一般根据服务器的 CPU 核数来定,这样可以完美利用多核资源。 ```js -const cluster = require('cluster'); -const http = require('http'); -const numCPUs = require('os').cpus().length; +const cluster = require("cluster"); +const http = require("http"); +const numCPUs = require("os").cpus().length; if (cluster.isMaster) { // Fork workers. @@ -38,7 +38,7 @@ if (cluster.isMaster) { cluster.fork(); } - cluster.on('exit', (worker, code, signal) => { + cluster.on("exit", (worker, code, signal) => { console.log(`worker ${worker.process.pid} died`); }); } else { @@ -47,11 +47,12 @@ if (cluster.isMaster) { http .createServer((req, res) => { res.writeHead(200); - res.end('hello world\n'); + res.end("hello world\n"); }) .listen(8000); } ``` + ## 框架的多进程模型 上面的示例是否很简单呢?但作为企业级应用解决方案,我们需要考虑的问题还有很多。 @@ -177,23 +178,24 @@ module.exports = agent => { ```js // app.js -module.exports = app => { - app.messenger.on('xxx_action', data => { +module.exports = (app) => { + app.messenger.on("xxx_action", (data) => { // ... }); }; ``` 这个例子中,`agent.js` 的代码将在 Agent 进程上执行,`app.js` 的代码则在 Worker 进程上执行。它们通过框架封装的 `messenger` 对象进行进程间通信(IPC)。后续章节会对框架的 IPC 进行详细讲解。 + ### Master VS Agent VS Worker 应用启动时,会同时创建三类进程。下表概述了每种进程的数量、作用、稳定性以及是否运行业务代码: -| 类型 | 进程数量 | 作用 | 稳定性 | 是否运行业务代码 | -| ------ | ------------------ | -------------------------- | ------ | ---------------- | -| Master | 1 | 进程管理,进程间消息转发 | 非常高 | 否 | +| 类型 | 进程数量 | 作用 | 稳定性 | 是否运行业务代码 | +| ------ | ------------------- | ---------------------------- | ------ | ---------------- | +| Master | 1 | 进程管理,进程间消息转发 | 非常高 | 否 | | Agent | 1 | 后台运行工作(长连接客户端) | 高 | 少量 | -| Worker | 通常设置为 CPU 核数 | 执行业务代码 | 一般 | 是 | +| Worker | 通常设置为 CPU 核数 | 执行业务代码 | 一般 | 是 | #### Master @@ -222,17 +224,17 @@ Worker 进程因运行复杂的业务代码,稳定性相对较低。一旦 Wor 尽管 Worker 进程相对独立,它们间仍需通讯。以下是 Node.js 官方的 IPC 示例代码: ```js -'use strict'; -const cluster = require('cluster'); +"use strict"; +const cluster = require("cluster"); if (cluster.isMaster) { const worker = cluster.fork(); - worker.send('hi there'); - worker.on('message', (msg) => { + worker.send("hi there"); + worker.on("message", (msg) => { console.log(`msg: ${msg} from worker#${worker.id}`); }); } else if (cluster.isWorker) { - process.on('message', (msg) => { + process.on("message", (msg) => { process.send(msg); }); } @@ -273,12 +275,12 @@ if (cluster.isMaster) { - `app.messenger.broadcast(action, data)`: 向所有的 agent / app 进程发送消息(包括自己)。 - `app.messenger.sendToApp(action, data)`: 发送至所有的 app 进程。 - - app 上调用即发送至自己与其他 app + - app 上调用即发送至自己与其他 app - agent 上调用则发送至所有 app 进程。 - `app.messenger.sendToAgent(action, data)`: 发送消息至 agent 进程。 - app 上调用即发送至 agent - agent 上调用即发送至自己。 -- `agent.messenger.sendRandom(action, data)`: +- `agent.messenger.sendRandom(action, data)`: - app 上无此方法(Egg 实现与 sentToAgent 类似) - agent 随机向某 app 进程发送消息(由 master 控制)。 - `app.messenger.sendTo(pid, action, data)`: 向指定进程发送消息。 @@ -287,9 +289,9 @@ if (cluster.isMaster) { // app.js module.exports = (app) => { // 只有在 egg-ready 事件后才能发送消息 - app.messenger.once('egg-ready', () => { - app.messenger.sendToAgent('agent-event', { foo: 'bar' }); - app.messenger.sendToApp('app-event', { foo: 'bar' }); + app.messenger.once("egg-ready", () => { + app.messenger.sendToAgent("agent-event", { foo: "bar" }); + app.messenger.sendToApp("app-event", { foo: "bar" }); }); }; ``` @@ -348,14 +350,14 @@ class SourceService extends Service { async checkUpdate() { // check if remote data source has changed const updated = await mockCheck(); - this.ctx.logger.info('check update response %s', updated); + this.ctx.logger.info("check update response %s", updated); return updated; } async update() { // update memory cache from remote memoryCache = await mockFetch(); - this.ctx.logger.info('update memory cache from remote: %j', memoryCache); + this.ctx.logger.info("update memory cache from remote: %j", memoryCache); } } ``` @@ -365,13 +367,13 @@ class SourceService extends Service { ```js // app/schedule/force_refresh.js exports.schedule = { - interval: '10m', - type: 'all' // 在所有的 workers 中运行 + interval: "10m", + type: "all", // 在所有的 workers 中运行 }; exports.task = async (ctx) => { await ctx.service.source.update(); - ctx.app.lastUpdateBy = 'force'; + ctx.app.lastUpdateBy = "force"; }; ``` @@ -380,8 +382,8 @@ exports.task = async (ctx) => { ```js // app/schedule/pull_refresh.js exports.schedule = { - interval: '10s', - type: 'worker' // 只在一个 worker 中运行 + interval: "10s", + type: "worker", // 只在一个 worker 中运行 }; exports.task = async (ctx) => { @@ -389,7 +391,7 @@ exports.task = async (ctx) => { if (!needRefresh) return; // notify all workers to update memory cache from `file` - ctx.app.messenger.sendToApp('refresh', 'pull'); + ctx.app.messenger.sendToApp("refresh", "pull"); }; ``` @@ -398,8 +400,8 @@ exports.task = async (ctx) => { ```js // app.js module.exports = (app) => { - app.messenger.on('refresh', (by) => { - app.logger.info('start update by %s', by); + app.messenger.on("refresh", (by) => { + app.logger.info("start update by %s", by); // 创建一个匿名 context 来访问 service const ctx = app.createAnonymousContext(); ctx.runInBackground(async () => { @@ -415,12 +417,12 @@ module.exports = (app) => { ```js // agent.js -const Subscriber = require('./lib/subscriber'); +const Subscriber = require("./lib/subscriber"); module.exports = (agent) => { const subscriber = new Subscriber(); // 监听变更事件,广播到所有 workers - subscriber.on('changed', () => agent.messenger.sendToApp('refresh', 'push')); + subscriber.on("changed", () => agent.messenger.sendToApp("refresh", "push")); }; ``` diff --git a/site/docs/core/cookie-and-session.md b/site/docs/core/cookie-and-session.md index 13bcc3a82e..40feff52ae 100644 --- a/site/docs/core/cookie-and-session.md +++ b/site/docs/core/cookie-and-session.md @@ -20,14 +20,14 @@ By using `ctx.cookies`, we can easily and safely read/set cookies in controller. class HomeController extends Controller { async add() { const ctx = this.ctx; - let count = ctx.cookies.get('count'); + let count = ctx.cookies.get("count"); count = count ? Number(count) : 0; - ctx.cookies.set('count', ++count); + ctx.cookies.set("count", ++count); ctx.body = count; } async remove() { const ctx = this.ctx; - ctx.cookies.set('count', null); + ctx.cookies.set("count", null); ctx.status = 204; } } @@ -95,7 +95,7 @@ the corresponding options also need to be used in `get` method. If you want to get the cookie set by frontend or other system, you need to specify the parameter `signed` as `false`, avoid varify the cookie and not getting the vlaue. ```js -ctx.cookies.get('frontend-cookie', { +ctx.cookies.get("frontend-cookie", { signed: false, }); ``` @@ -107,7 +107,7 @@ In `config/config.default.js`: ```js module.exports = { - keys: 'key1,key2', + keys: "key1,key2", }; ``` @@ -164,7 +164,7 @@ What you need to pay special attention to is that you need to avoid the followin ```js // ❌ Wrong way ctx.session._visited = 1; // --> property will lost -ctx.session.isNew = 'HeHe'; // --> session keyword, should not write it +ctx.session.isNew = "HeHe"; // --> session keyword, should not write it // ✔️ Right way ctx.session.visited = 1; // --> Everything is all right @@ -178,7 +178,7 @@ The default configuration of Session is: ```js exports.session = { - key: 'EGG_SESS', + key: "EGG_SESS", maxAge: 24 * 3600 * 1000, // 1 day httpOnly: true, encrypt: true, @@ -227,11 +227,11 @@ To apply it, import [egg-redis] and [egg-session-redis] plugin in your applicati // plugin.js exports.redis = { enable: true, - package: 'egg-redis', + package: "egg-redis", }; exports.sessionRedis = { enable: true, - package: 'egg-session-redis', + package: "egg-session-redis", }; ``` @@ -253,7 +253,7 @@ If it's selected, Session of this logged in user can live longer. This kind of per-user session expiration time can be set through `ctx.session.maxAge`: ```js -const ms = require('ms'); +const ms = require("ms"); class UserController extends Controller { async login() { const ctx = this.ctx; @@ -263,7 +263,7 @@ class UserController extends Controller { // set Session ctx.session.user = user; // if user selected `Remember Me`, set expiration time to 30 days - if (rememberMe) ctx.session.maxAge = ms('30d'); + if (rememberMe) ctx.session.maxAge = ms("30d"); } } ``` diff --git a/site/docs/core/cookie-and-session.zh-CN.md b/site/docs/core/cookie-and-session.zh-CN.md index 6ed1278a47..9692f5750e 100644 --- a/site/docs/core/cookie-and-session.zh-CN.md +++ b/site/docs/core/cookie-and-session.zh-CN.md @@ -13,14 +13,14 @@ HTTP 请求都是无状态的,但是我们的 Web 应用通常都需要知道 class HomeController extends Controller { async add() { const ctx = this.ctx; - let count = ctx.cookies.get('count'); + let count = ctx.cookies.get("count"); count = count ? Number(count) : 0; - ctx.cookies.set('count', ++count); + ctx.cookies.set("count", ++count); ctx.body = count; } async remove() { const ctx = this.ctx; - ctx.cookies.set('count', null); + ctx.cookies.set("count", null); ctx.status = 204; } } @@ -52,7 +52,7 @@ class HomeController extends Controller { ```js ctx.cookies.set(key, value, { httpOnly: false, - signed: false + signed: false, }); ``` @@ -61,7 +61,7 @@ ctx.cookies.set(key, value, { ```js ctx.cookies.set(key, value, { httpOnly: true, // 默认就是 true - encrypt: true // 加密传输 + encrypt: true, // 加密传输 }); ``` @@ -80,8 +80,8 @@ ctx.cookies.set(key, value, { 如果要获取前端或者其他系统设置的 cookie,需要指定参数 `signed` 为 `false`,避免验签导致获取不到 cookie 的值。 ```js -ctx.cookies.get('frontend-cookie', { - signed: false +ctx.cookies.get("frontend-cookie", { + signed: false, }); ``` @@ -91,7 +91,7 @@ ctx.cookies.get('frontend-cookie', { ```js module.exports = { - keys: 'key1,key2' + keys: "key1,key2", }; ``` @@ -101,6 +101,7 @@ keys 配置成一个字符串,可以按照逗号分隔配置多个 key。Cooki - 解密和验签时会遍历 keys 进行解密。 如果我们想要更新 Cookie 的秘钥,但是又不希望之前设置到用户浏览器上的 Cookie 失效,可以将新的秘钥配置到 keys 最前面,等过一段时间之后再删除不需要的秘钥即可。 + ## Session Cookie 通常用作 Web 应用中标识请求方身份的功能,基于此,Web 应用封装了 Session 概念,专用于用户身份识别。 @@ -138,7 +139,7 @@ ctx.session = null; ```js // ❌ 错误的用法 ctx.session._visited = 1; // 该字段会在下一次请求时丢失 -ctx.session.isNew = 'HeHe'; // 为内部关键字,不应更改 +ctx.session.isNew = "HeHe"; // 为内部关键字,不应更改 // ✔️ 正确的用法 ctx.session.visited = 1; // 无问题 @@ -148,7 +149,7 @@ Session 默认基于 Cookie 实现,内容加密后直接存储在 Cookie 的 ```js exports.session = { - key: 'EGG_SESS', + key: "EGG_SESS", maxAge: 24 * 3600 * 1000, // 1 天 httpOnly: true, encrypt: true, @@ -165,7 +166,7 @@ Session 默认存放在 Cookie 中可能出现问题:浏览器有最大 Cookie ```js // app.js -module.exports = app => { +module.exports = (app) => { app.sessionStore = { async get(key) { // 返回值 @@ -186,11 +187,11 @@ module.exports = app => { // plugin.js exports.redis = { enable: true, - package: 'egg-redis', + package: "egg-redis", }; exports.sessionRedis = { enable: true, - package: 'egg-session-redis', + package: "egg-session-redis", }; ``` @@ -203,7 +204,7 @@ exports.sessionRedis = { Session 配置中的 `maxAge` 可全局设置有效期。**记住我** 功能中,可针对特定用户的 Session 设置不同有效时间,通过 `ctx.session.maxAge=` 实现: ```js -const ms = require('ms'); +const ms = require("ms"); class UserController extends Controller { async login() { const ctx = this.ctx; @@ -213,7 +214,7 @@ class UserController extends Controller { // 设置 Session ctx.session.user = user; // 勾选 `记住我` 时,设置 30 天过期时间 - if (rememberMe) ctx.session.maxAge = ms('30d'); + if (rememberMe) ctx.session.maxAge = ms("30d"); } } ``` diff --git a/site/docs/core/deployment.md b/site/docs/core/deployment.md index a9ff392b5d..93c7d9f169 100644 --- a/site/docs/core/deployment.md +++ b/site/docs/core/deployment.md @@ -88,7 +88,7 @@ Arguments of dispatch can be configured in `config.{env}.js`. exports.cluster = { listen: { port: 7001, - hostname: '127.0.0.1', // It is not recommended to set the hostname to '0.0.0.0', which will allow connections from external networks and sources, please use it if you know the risk. + hostname: "127.0.0.1", // It is not recommended to set the hostname to '0.0.0.0', which will allow connections from external networks and sources, please use it if you know the risk. // path: '/var/run/egg.sock', }, }; diff --git a/site/docs/core/deployment.zh-CN.md b/site/docs/core/deployment.zh-CN.md index a5c7534acb..49d2e50734 100644 --- a/site/docs/core/deployment.zh-CN.md +++ b/site/docs/core/deployment.zh-CN.md @@ -89,7 +89,7 @@ $ egg-scripts start --port=7001 --daemon --title=egg-server-showcase exports.cluster = { listen: { port: 7001, - hostname: '127.0.0.1', // 不建议设置为 '0.0.0.0',可能导致外部连接风险,请了解后使用 + hostname: "127.0.0.1", // 不建议设置为 '0.0.0.0',可能导致外部连接风险,请了解后使用 // path: '/var/run/egg.sock', }, }; @@ -110,6 +110,7 @@ $ egg-scripts stop [--title=egg-server] - `--title=egg-server`:杀死指定 Egg 应用,未设置则终止所有 Egg 应用。 也可通过 `ps -eo "pid,command" | grep -- "--title=egg-server"` 查找 master 进程,并 `kill` 掉,不需 `kill -9`。 + ## 监控 我们还需要对服务进行性能监控、内存泄露分析、故障排除等。 @@ -158,7 +159,7 @@ $ npm i egg-alinode --save // config/plugin.js exports.alinode = { enable: true, - package: 'egg-alinode', + package: "egg-alinode", }; ``` @@ -168,8 +169,8 @@ exports.alinode = { // config/config.default.js exports.alinode = { // 从 `Node.js 性能平台` 获取对应的接入参数 - appid: '', - secret: '', + appid: "", + secret: "", }; ``` diff --git a/site/docs/core/development.md b/site/docs/core/development.md index 94c21efc6c..3f3be3481d 100644 --- a/site/docs/core/development.md +++ b/site/docs/core/development.md @@ -207,13 +207,13 @@ There's a built-in [Log](./logger.md) in the egg, so you may use logger.debug() ```js // controller -this.logger.debug('current user: %j', this.user); +this.logger.debug("current user: %j", this.user); // service -this.ctx.logger.debug('debug info from service'); +this.ctx.logger.debug("debug info from service"); // app/init.js -app.logger.debug('app init'); +app.logger.debug("app init"); ``` Levels of logs can be configured via `config.logger.level` for printing into file, and `config.logger.consoleLevel` for printing into console. diff --git a/site/docs/core/development.zh-CN.md b/site/docs/core/development.zh-CN.md index 4b53e175ca..7ed06a2a10 100644 --- a/site/docs/core/development.zh-CN.md +++ b/site/docs/core/development.zh-CN.md @@ -69,6 +69,7 @@ $ npm i egg-bin --save-dev } } ``` + ## 单元测试 这里主要讲解工具部分的使用,更多关于单元测试的内容请参考[这里](./unittest.md)。 @@ -141,7 +142,6 @@ $ # 支持 mocha 参数,如 grep、require 等 $ npm test -- -t 30000 --grep="should GET" ``` - ## 代码覆盖率 egg-bin 已内置 [nyc](https://github.com/istanbuljs/nyc) 支持单元测试生成代码覆盖率报告。 @@ -196,6 +196,7 @@ $ COV_EXCLUDES=app/plugins/c* npm run cov $ # 或者使用传参方式 $ npm run cov -- --x=app/plugins/c* ``` + ## 调试 ### 日志输出 @@ -206,13 +207,13 @@ $ npm run cov -- --x=app/plugins/c* ```js // controller -this.logger.debug('current user: %j', this.user); +this.logger.debug("current user: %j", this.user); // service -this.ctx.logger.debug('debug info from service'); +this.ctx.logger.debug("debug info from service"); // app/init.js -app.logger.debug('app init'); +app.logger.debug("app init"); ``` 通过 `config.logger.level` 来配置打印到文件的日志级别,通过 `config.logger.consoleLevel` 配置打印到终端的日志级别。 @@ -238,6 +239,7 @@ $ DEBUG=egg* npm run dev ``` 单元测试也可以使用 `DEBUG=* npm test` 来查看测试用例运行的详细日志。 + ### 使用 egg-bin 调试 #### 添加命令 @@ -331,7 +333,7 @@ DevTools → chrome-devtools://devtools/bundled/inspector.html?experiments=true& "cwd": "${workspaceRoot}", "runtimeExecutable": "npm", "windows": { "runtimeExecutable": "npm.cmd" }, - "runtimeArgs": [ "run", "debug" ], + "runtimeArgs": ["run", "debug"], "console": "integratedTerminal", "protocol": "auto", "restart": true, diff --git a/site/docs/core/error-handling.md b/site/docs/core/error-handling.md index 490ec444a1..a92e3bce60 100644 --- a/site/docs/core/error-handling.md +++ b/site/docs/core/error-handling.md @@ -12,10 +12,10 @@ With those features, you can take following implementation as reference: ```js // app/service/test.js try { - const res = await this.ctx.curl('http://eggjs.com/api/echo', { - dataType: 'json', + const res = await this.ctx.curl("http://eggjs.com/api/echo", { + dataType: "json", }); - if (res.status !== 200) throw new Error('response status is not 200'); + if (res.status !== 200) throw new Error("response status is not 200"); return res.data; } catch (err) { this.logger.error(err); @@ -80,7 +80,7 @@ Redirecting to your customized error page by setting `errorPageUrl` in `onerror` ```js module.exports = { onerror: { - errorPageUrl: '/50x.html', + errorPageUrl: "/50x.html", }, }; ``` @@ -140,7 +140,7 @@ Overriding default 404 page to the one you want: // config/config.default.js module.exports = { notfound: { - pageUrl: '/404.html', + pageUrl: "/404.html", }, }; ``` @@ -156,9 +156,9 @@ module.exports = () => { await next(); if (ctx.status === 404 && !ctx.body) { if (ctx.acceptJSON) { - ctx.body = { error: 'Not Found' }; + ctx.body = { error: "Not Found" }; } else { - ctx.body = '

Page Not Found

'; + ctx.body = "

Page Not Found

"; } } }; @@ -170,6 +170,6 @@ Adding yours to `middleware` in config: ```js // config/config.default.js module.exports = { - middleware: ['notfoundHandler'], + middleware: ["notfoundHandler"], }; ``` diff --git a/site/docs/core/error-handling.zh-CN.md b/site/docs/core/error-handling.zh-CN.md index 512af4c547..092584defd 100644 --- a/site/docs/core/error-handling.zh-CN.md +++ b/site/docs/core/error-handling.zh-CN.md @@ -10,10 +10,10 @@ order: 9 ```js // app/service/test.js try { - const res = await this.ctx.curl('http://eggjs.com/api/echo', { - dataType: 'json' + const res = await this.ctx.curl("http://eggjs.com/api/echo", { + dataType: "json", }); - if (res.status !== 200) throw new Error('response status is not 200'); + if (res.status !== 200) throw new Error("response status is not 200"); return res.data; } catch (err) { this.logger.error(err); @@ -31,7 +31,7 @@ class HomeController extends Controller { const config = await this.ctx.service.trade.buy(request); // 下单后需要进行一次核对,且不阻塞当前请求 setImmediate(() => { - this.ctx.service.trade.check(request).catch(err => this.ctx.logger.error(err)); + this.ctx.service.trade.check(request).catch((err) => this.ctx.logger.error(err)); }); } } @@ -61,13 +61,13 @@ class HomeController extends Controller { 框架通过 [onerror](https://github.com/eggjs/egg-onerror) 插件提供统一的错误处理机制。此机制将捕获所有处理方法(Middleware、Controller、Service)中抛出的任何异常,并根据请求预期的响应类型返回不同的错误内容。 -| 请求格式需求 | 环境 | `errorPageUrl` 配置 | 返回内容 | -| ------------ | ---- | ------------------- | -------- | -| HTML & TEXT | local & unittest | - | onerror 提供的详细错误页面 | -| HTML & TEXT | 其他 | 是 | 重定向至 `errorPageUrl` | -| HTML & TEXT | 其他 | 否 | 简易错误页(不含错误信息) | -| JSON & JSONP | local & unittest | - | 详细错误信息的 JSON 或 JSONP 响应 | -| JSON & JSONP | 其他 | - | 不含详细错误信息的 JSON 或 JSONP 响应 | +| 请求格式需求 | 环境 | `errorPageUrl` 配置 | 返回内容 | +| ------------ | ---------------- | ------------------- | ------------------------------------- | +| HTML & TEXT | local & unittest | - | onerror 提供的详细错误页面 | +| HTML & TEXT | 其他 | 是 | 重定向至 `errorPageUrl` | +| HTML & TEXT | 其他 | 否 | 简易错误页(不含错误信息) | +| JSON & JSONP | local & unittest | - | 详细错误信息的 JSON 或 JSONP 响应 | +| JSON & JSONP | 其他 | - | 不含详细错误信息的 JSON 或 JSONP 响应 | ### errorPageUrl @@ -78,8 +78,8 @@ class HomeController extends Controller { module.exports = { onerror: { // 线上发生异常时,重定向到此页面 - errorPageUrl: '/50x.html' - } + errorPageUrl: "/50x.html", + }, }; ``` @@ -94,25 +94,26 @@ module.exports = { all(err, ctx) { // 定义所有响应类型的错误处理方法 // 定义了 config.all 后,其他错误处理不再生效 - ctx.body = 'error'; + ctx.body = "error"; ctx.status = 500; }, html(err, ctx) { // HTML 错误处理 - ctx.body = '

error

'; + ctx.body = "

error

"; ctx.status = 500; }, json(err, ctx) { // JSON 错误处理 - ctx.body = { message: 'error' }; + ctx.body = { message: "error" }; ctx.status = 500; }, jsonp(err, ctx) { // JSONP 错误一般不需特殊处理,自动调用 JSON 方法 - } - } + }, + }, }; ``` + 框架并不会将服务端返回的 404 状态当做异常来处理,但是框架提供了当响应为 404 且没有返回 body 时的默认响应。 - 当请求被框架判定为需要 JSON 格式的响应时,会返回一段 JSON: @@ -132,9 +133,9 @@ module.exports = { ```js // config/config.default.js module.exports = { - notfound: { - pageUrl: '/404.html', - }, + notfound: { + pageUrl: "/404.html", + }, }; ``` @@ -145,16 +146,16 @@ module.exports = { ```js // app/middleware/notfound_handler.js module.exports = () => { - return async function notFoundHandler(ctx, next) { - await next(); - if (ctx.status === 404 && !ctx.body) { - if (ctx.acceptJSON) { - ctx.body = { error: 'Not Found' }; - } else { - ctx.body = '

Page Not Found

'; - } - } - }; + return async function notFoundHandler(ctx, next) { + await next(); + if (ctx.status === 404 && !ctx.body) { + if (ctx.acceptJSON) { + ctx.body = { error: "Not Found" }; + } else { + ctx.body = "

Page Not Found

"; + } + } + }; }; ``` @@ -163,6 +164,6 @@ module.exports = () => { ```js // config/config.default.js module.exports = { - middleware: ['notfoundHandler'], + middleware: ["notfoundHandler"], }; ``` diff --git a/site/docs/core/httpclient.md b/site/docs/core/httpclient.md index 184a4690f6..7f58403a6e 100644 --- a/site/docs/core/httpclient.md +++ b/site/docs/core/httpclient.md @@ -19,10 +19,10 @@ So you can easily use `app.curl` to complete a HTTP request. module.exports = (app) => { app.beforeStart(async () => { // example: read the version info on https://registry.npmmirror.com/egg/latest when it starts - const result = await app.curl('https://registry.npmmirror.com/egg/latest', { - dataType: 'json', + const result = await app.curl("https://registry.npmmirror.com/egg/latest", { + dataType: "json", }); - app.logger.info('Egg latest version: %s', result.data.version); + app.logger.info("Egg latest version: %s", result.data.version); }); }; ``` @@ -39,9 +39,9 @@ class NpmController extends Controller { const ctx = this.ctx; // example: request a npm module's info - const result = await ctx.curl('https://registry.npmmirror.com/egg/latest', { + const result = await ctx.curl("https://registry.npmmirror.com/egg/latest", { // parse JSON response - dataType: 'json', + dataType: "json", // timeout of 3s timeout: 3000, }); @@ -70,7 +70,7 @@ Reading data almost uses GET request. It is the most common type and widely used class NpmController extends Controller { async get() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/get?foo=bar'); + const result = await ctx.curl("https://httpbin.org/get?foo=bar"); ctx.status = result.status; ctx.set(result.headers); ctx.body = result.data; @@ -98,17 +98,17 @@ Take sending JSON boy as example: class NpmController extends Controller { async post() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/post', { + const result = await ctx.curl("https://httpbin.org/post", { // method is required - method: 'POST', + method: "POST", // telling HttpClient to send data as JSON by contentType - contentType: 'json', + contentType: "json", data: { - hello: 'world', + hello: "world", now: Date.now(), }, // telling HttpClient to process the return body as JSON format explicitly - dataType: 'json', + dataType: "json", }); ctx.body = result.data; } @@ -126,16 +126,16 @@ Similar to POST, but PUT is better for data updating and replacement. Almost the class NpmController extends Controller { async put() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/put', { + const result = await ctx.curl("https://httpbin.org/put", { // method is required - method: 'PUT', + method: "PUT", // telling HttpClient to send data as JSON by contentType - contentType: 'json', + contentType: "json", data: { - update: 'foo bar', + update: "foo bar", }, // telling HttpClient to process the return body as JSON format explicitly - dataType: 'json', + dataType: "json", }); ctx.body = result.data; } @@ -151,11 +151,11 @@ DELETE request is to delete the data, request body don't need to add request bod class NpmController extends Controller { async del() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/delete', { + const result = await ctx.curl("https://httpbin.org/delete", { // method is required - method: 'DELETE', + method: "DELETE", // telling HttpClient to process the return body as JSON format explicitly - dataType: 'json', + dataType: "json", }); ctx.body = result.data; } @@ -175,16 +175,16 @@ Interfaces of Browser-Oriented Form Submission (without files), usually require class NpmController extends Controller { async submit() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/post', { + const result = await ctx.curl("https://httpbin.org/post", { // method is required, supports POST,PUT and DELETE - method: 'POST', + method: "POST", // contentType is not needed, by default HttpClient will send request in application/x-www-form-urlencoded data: { now: Date.now(), - foo: 'bar', + foo: "bar", }, // telling HttpClient to process the return body as JSON format explicitly - dataType: 'json', + dataType: "json", }); ctx.body = result.data.form; // final response will similar as below: @@ -207,11 +207,11 @@ class HttpController extends Controller { async upload() { const { ctx } = this; - const result = await ctx.curl('https://httpbin.org/post', { - method: 'POST', - dataType: 'json', + const result = await ctx.curl("https://httpbin.org/post", { + method: "POST", + dataType: "json", data: { - foo: 'bar', + foo: "bar", }, // one file @@ -241,8 +241,8 @@ If the server supports streaming, the most friendly way is to send the Stream di ```js // app/controller/npm.js -const fs = require('fs'); -const FormStream = require('formstream'); +const fs = require("fs"); +const FormStream = require("formstream"); class NpmController extends Controller { async uploadByStream() { const ctx = this.ctx; @@ -252,7 +252,7 @@ class NpmController extends Controller { const url = `${ctx.protocol}://${ctx.host}/stream`; const result = await ctx.curl(url, { // method is required, supports POST,PUT - method: 'POST', + method: "POST", // submitted by stream mode stream: fileStream, }); @@ -330,20 +330,20 @@ The request data will select the correct processing method automatically based o ```js // GET + data ctx.curl(url, { - data: { foo: 'bar' }, + data: { foo: "bar" }, }); // POST + data ctx.curl(url, { - method: 'POST', - data: { foo: 'bar' }, + method: "POST", + data: { foo: "bar" }, }); // POST + JSON + data ctx.curl(url, { - method: 'POST', - contentType: 'json', - data: { foo: 'bar' }, + method: "POST", + contentType: "json", + data: { foo: "bar" }, }); ``` @@ -355,11 +355,11 @@ The application scenarios that sending data using `stream` and pass additional r ```js ctx.curl(url, { - method: 'POST', + method: "POST", dataAsQueryString: true, data: { // generally it would be some validation parameters such as access token, etc. - accessToken: 'some access token value', + accessToken: "some access token value", }, stream: myFileStream, }); @@ -371,11 +371,11 @@ Set request Context, if the parameter is set, it will ignore the `data` paramete ```js ctx.curl(url, { - method: 'POST', + method: "POST", // Sending the raw xml data without HttpClient's to do processing - content: 'world', + content: "world", headers: { - 'content-type': 'text/html', + "content-type": "text/html", }, }); ``` @@ -386,10 +386,10 @@ File upload, support: `String | ReadStream | Buffer | Array | Object`. ```js ctx.curl(url, { - method: 'POST', - files: '/path/to/read', + method: "POST", + files: "/path/to/read", data: { - foo: 'other fields', + foo: "other fields", }, }); ``` @@ -398,14 +398,14 @@ upload multiple files: ```js ctx.curl(url, { - method: 'POST', + method: "POST", files: { - file1: '/path/to/read', + file1: "/path/to/read", file2: fs.createReadStream(__filename), - file3: Buffer.from('mock file content'), + file3: Buffer.from("mock file content"), }, data: { - foo: 'other fields', + foo: "other fields", }, }); ``` @@ -417,8 +417,8 @@ If the parameter is set , HttpClient will ignore `data` and `content` ```js ctx.curl(url, { - method: 'POST', - stream: fs.createReadStream('/path/to/read'), + method: "POST", + stream: fs.createReadStream("/path/to/read"), }); ``` @@ -429,7 +429,7 @@ Once the parameter is set, response `result.data` is set to `null` because all d ```js ctx.curl(url, { - writeStream: fs.createWriteStream('/path/to/store'), + writeStream: fs.createWriteStream("/path/to/store"), }); ``` @@ -451,12 +451,12 @@ If need to send `data` by JSON ```js ctx.curl(url, { - method: 'POST', + method: "POST", data: { - foo: 'bar', + foo: "bar", now: Date.now(), }, - contentType: 'json', + contentType: "json", }); ``` @@ -468,12 +468,12 @@ Set the response data format, default return the raw buffer formatted data witho ```js const jsonResult = await ctx.curl(url, { - dataType: 'json', + dataType: "json", }); console.log(jsonResult.data); const htmlResult = await ctx.curl(url, { - dataType: 'text', + dataType: "text", }); console.log(htmlResult.data); ``` @@ -486,7 +486,7 @@ Typically, the JSON data returned by some CGI system might contains such special ```js ctx.curl(url, { fixJSONCtlChars: true, - dataType: 'json', + dataType: "json", }); ``` @@ -497,7 +497,7 @@ Custom request headers ```js ctx.curl(url, { headers: { - 'x-foo': 'bar', + "x-foo": "bar", }, }); ``` @@ -545,7 +545,7 @@ Parameter of Simple login authorization (Basic Authentication), will send the lo ```js ctx.curl(url, { // parameter must follow the format of `user:password` - auth: 'foo:bar', + auth: "foo:bar", }); ``` @@ -556,7 +556,7 @@ Parameter of the Digest Authentication. If the parameter is set, it will attempt ```js ctx.curl(url, { // parameter must follow the format of `user:password` - digestAuth: 'foo:bar', + digestAuth: "foo:bar", }); ``` @@ -591,8 +591,8 @@ ctx.curl(url, { ctx.curl(url, { formatRedirectUrl: (from, to) => { // for example you can correct the redirection of wrong url here - if (to === '//foo/') { - to = '/foo'; + if (to === "//foo/") { + to = "/foo"; } return url.resolve(from, to); }, @@ -607,7 +607,7 @@ HttpClient will attempt to invoke the `beforeRequest` hook before requesting off ctx.curl(url, { beforeRequest: (options) => { // For example, we can set the global request ID to facilitate log tracking - options.headers['x-request-id'] = uuid.v1(); + options.headers["x-request-id"] = uuid.v1(); }, }); ``` @@ -773,7 +773,7 @@ To facilitate monitoring HttpClient requests and responses on the app level, we A `request` event is triggered before the request is sent, allowing blocking of the request. ```js -app.httpclient.on('request', (req) => { +app.httpclient.on("request", (req) => { req.url; //request url req.ctx; //context of the request @@ -786,7 +786,7 @@ app.httpclient.on('request', (req) => { After the end of request, a `response` event is triggered, so that the external event can be subscribed to the log printing. ```js -app.httpclient.on('response', (result) => { +app.httpclient.on("response", (result) => { result.res.status; result.ctx; //context of the request result.req; //the corresponding req object, which the req in the request event @@ -797,8 +797,8 @@ app.httpclient.on('response', (result) => { Full examples can be found on [eggjs/examples/httpclient](https://github.com/eggjs/examples/blob/master/httpclient) . - Other Reference Links + - [urllib](https://github.com/node-modules/urllib) - [httpclient](https://github.com/eggjs/egg/blob/master/lib/core/httpclient.js) - [formstream](https://github.com/node-modules/formstream) diff --git a/site/docs/core/httpclient.zh-CN.md b/site/docs/core/httpclient.zh-CN.md index 6e3065755e..f4f3c97741 100644 --- a/site/docs/core/httpclient.zh-CN.md +++ b/site/docs/core/httpclient.zh-CN.md @@ -15,13 +15,13 @@ order: 5 ```js // app.js -module.exports = app => { +module.exports = (app) => { app.beforeStart(async () => { // 示例:启动时去读取 https://registry.npmmirror.com/egg/latest 的版本信息 - const result = await app.curl('https://registry.npmmirror.com/egg/latest', { - dataType: 'json', + const result = await app.curl("https://registry.npmmirror.com/egg/latest", { + dataType: "json", }); - app.logger.info('Egg 最新版本:%s', result.data.version); + app.logger.info("Egg 最新版本:%s", result.data.version); }); }; ``` @@ -37,9 +37,9 @@ class NpmController extends Controller { const ctx = this.ctx; // 示例:请求一个 npm 模块信息 - const result = await ctx.curl('https://registry.npmmirror.com/egg/latest', { + const result = await ctx.curl("https://registry.npmmirror.com/egg/latest", { // 自动解析 JSON 响应 - dataType: 'json', + dataType: "json", // 3 秒超时 timeout: 3000, }); @@ -52,6 +52,7 @@ class NpmController extends Controller { } } ``` + ## 基本 HTTP 请求 HTTP 已经被广泛大量使用。尽管 HTTP 有多种请求方式,但是万变不离其宗。我们先以基本的四个请求方法为例子,逐步讲解一下更多的复杂应用场景。 @@ -67,13 +68,12 @@ HTTP 已经被广泛大量使用。尽管 HTTP 有多种请求方式,但是万 class NpmController extends Controller { async get() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/get?foo=bar'); + const result = await ctx.curl("https://httpbin.org/get?foo=bar"); ctx.status = result.status; ctx.set(result.headers); ctx.body = result.data; } } - ``` - GET 请求可以不用设置 `options.method` 参数,`HttpClient` 的默认 `method` 会设置为 `GET`。 @@ -96,22 +96,21 @@ class NpmController extends Controller { class NpmController extends Controller { async post() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/post', { + const result = await ctx.curl("https://httpbin.org/post", { // 必须指定 method - method: 'POST', + method: "POST", // 通过 contentType 告诉 HttpClient 以 JSON 格式发送 - contentType: 'json', + contentType: "json", data: { - hello: 'world', + hello: "world", now: Date.now(), }, // 明确告诉 HttpClient 以 JSON 格式处理返回的响应 body - dataType: 'json', + dataType: "json", }); ctx.body = result.data; } } - ``` 下文还会详细讲解以 POST 实现表单提交和文件上传的功能。 @@ -126,21 +125,20 @@ PUT 与 POST 类似,它更加适合更新数据和替换数据的语义。 class NpmController extends Controller { async put() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/put', { + const result = await ctx.curl("https://httpbin.org/put", { // 必须指定 method - method: 'PUT', + method: "PUT", // 通过 contentType 告诉 HttpClient 以 JSON 格式发送 - contentType: 'json', + contentType: "json", data: { - update: 'foo bar', + update: "foo bar", }, // 明确告诉 HttpClient 以 JSON 格式处理响应 body - dataType: 'json', + dataType: "json", }); ctx.body = result.data; } } - ``` ### DELETE @@ -152,17 +150,17 @@ class NpmController extends Controller { class NpmController extends Controller { async del() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/delete', { + const result = await ctx.curl("https://httpbin.org/delete", { // 必须指定 method - method: 'DELETE', + method: "DELETE", // 明确告诉 HttpClient 以 JSON 格式处理响应 body - dataType: 'json', + dataType: "json", }); ctx.body = result.data; } } - ``` + ## 高级 HTTP 请求 在真实的应用场景下,还会包含一些较为复杂的 HTTP 请求。 @@ -176,16 +174,16 @@ class NpmController extends Controller { class NpmController extends Controller { async submit() { const ctx = this.ctx; - const result = await ctx.curl('https://httpbin.org/post', { + const result = await ctx.curl("https://httpbin.org/post", { // 必须指定 method,支持 POST,PUT 和 DELETE - method: 'POST', + method: "POST", // 不需要设置 contentType,HttpClient 会默认以 application/x-www-form-urlencoded 格式发送请求 data: { now: Date.now(), - foo: 'bar', + foo: "bar", }, // 明确告诉 HttpClient 以 JSON 格式处理响应 body - dataType: 'json', + dataType: "json", }); ctx.body = result.data.form; // 响应最终会是类似以下的结果: @@ -209,16 +207,16 @@ class HttpController extends Controller { async upload() { const { ctx } = this; - const result = await ctx.curl('https://httpbin.org/post', { - method: 'POST', - dataType: 'json', + const result = await ctx.curl("https://httpbin.org/post", { + method: "POST", + dataType: "json", data: { - foo: 'bar', + foo: "bar", }, - + // 单文件上传 files: __filename, - + // 多文件上传 // files: { // file1: __filename, @@ -242,8 +240,8 @@ class HttpController extends Controller { ```js // app/controller/npm.js -const fs = require('fs'); -const FormStream = require('formstream'); +const fs = require("fs"); +const FormStream = require("formstream"); class NpmController extends Controller { async uploadByStream() { const ctx = this.ctx; @@ -253,7 +251,7 @@ class NpmController extends Controller { const url = `${ctx.protocol}://${ctx.host}/stream`; const result = await ctx.curl(url, { // 必须指定 method,支持 POST,PUT - method: 'POST', + method: "POST", // 以 stream 模式提交 stream: fileStream, }); @@ -265,6 +263,7 @@ class NpmController extends Controller { } } ``` + ## options 参数详解 由于 HTTP 请求的复杂性,导致 `httpclient.request(url, options)` 的 options 参数会非常多。 @@ -286,7 +285,7 @@ exports.httpclient = { request: { // 默认 request 超时时间 - timeout: 3000 + timeout: 3000, }, httpAgent: { @@ -299,7 +298,7 @@ exports.httpclient = { // 允许创建的最大 socket 数 maxSockets: Number.MAX_SAFE_INTEGER, // 最大空闲 socket 数 - maxFreeSockets: 256 + maxFreeSockets: 256, }, httpsAgent: { @@ -312,8 +311,8 @@ exports.httpclient = { // 允许创建的最大 socket 数 maxSockets: Number.MAX_SAFE_INTEGER, // 最大空闲 socket 数 - maxFreeSockets: 256 - } + maxFreeSockets: 256, + }, }; ``` @@ -331,20 +330,20 @@ exports.httpclient = { ```javascript // GET + data ctx.curl(url, { - data: { foo: 'bar' } + data: { foo: "bar" }, }); // POST + data ctx.curl(url, { - method: 'POST', - data: { foo: 'bar' } + method: "POST", + data: { foo: "bar" }, }); // POST + JSON + data ctx.curl(url, { - method: 'POST', - contentType: 'json', - data: { foo: 'bar' } + method: "POST", + contentType: "json", + data: { foo: "bar" }, }); ``` @@ -357,13 +356,13 @@ ctx.curl(url, { ```javascript ctx.curl(url, { - method: 'POST', + method: "POST", dataAsQueryString: true, data: { // 通常是权限验证参数,如 access token - accessToken: 'some access token value' + accessToken: "some access token value", }, - stream: myFileStream + stream: myFileStream, }); ``` @@ -373,24 +372,25 @@ ctx.curl(url, { ```javascript ctx.curl(url, { - method: 'POST', + method: "POST", // 直接发送原始 XML 数据,不需 HttpClient 经行特殊处理 - content: 'world', + content: "world", headers: { - 'content-type': 'text/html' - } + "content-type": "text/html", + }, }); ``` + ### `files: Mixed` 文件上传,支持以下格式:`String | ReadStream | Buffer | Array | Object`。 ```js ctx.curl(url, { - method: 'POST', - files: '/path/to/read', + method: "POST", + files: "/path/to/read", data: { - foo: 'other fields', + foo: "other fields", }, }); ``` @@ -399,14 +399,14 @@ ctx.curl(url, { ```js ctx.curl(url, { - method: 'POST', + method: "POST", files: { - file1: '/path/to/read', + file1: "/path/to/read", file2: fs.createReadStream(__filename), - file3: Buffer.from('mock file content'), + file3: Buffer.from("mock file content"), }, data: { - foo: 'other fields', + foo: "other fields", }, }); ``` @@ -417,8 +417,8 @@ ctx.curl(url, { ```js ctx.curl(url, { - method: 'POST', - stream: fs.createReadStream('/path/to/read'), + method: "POST", + stream: fs.createReadStream("/path/to/read"), }); ``` @@ -428,7 +428,7 @@ ctx.curl(url, { ```js ctx.curl(url, { - writeStream: fs.createWriteStream('/path/to/store'), + writeStream: fs.createWriteStream("/path/to/store"), }); ``` @@ -448,12 +448,12 @@ ctx.curl(url, { ```js ctx.curl(url, { - method: 'POST', + method: "POST", data: { - foo: 'bar', + foo: "bar", now: Date.now(), }, - contentType: 'json', + contentType: "json", }); ``` @@ -465,12 +465,12 @@ ctx.curl(url, { ```js const jsonResult = await ctx.curl(url, { - dataType: 'json', + dataType: "json", }); console.log(jsonResult.data); const htmlResult = await ctx.curl(url, { - dataType: 'text', + dataType: "text", }); console.log(htmlResult.data); ``` @@ -482,7 +482,7 @@ console.log(htmlResult.data); ```js ctx.curl(url, { fixJSONCtlChars: true, - dataType: 'json', + dataType: "json", }); ``` @@ -493,10 +493,11 @@ ctx.curl(url, { ```js ctx.curl(url, { headers: { - 'x-foo': 'bar', + "x-foo": "bar", }, }); ``` + ### `timeout: Number|Array` 请求超时时间,默认是 `[5000, 5000]`,即创建连接超时是 5 秒,接收响应超时是 5 秒。 @@ -504,12 +505,12 @@ ctx.curl(url, { ```js ctx.curl(url, { // 创建连接超时 3 秒,接收响应超时 3 秒 - timeout: 3000 + timeout: 3000, }); ctx.curl(url, { // 创建连接超时 1 秒,接收响应超时 30 秒,用于响应比较大的场景 - timeout: [1000, 30000] + timeout: [1000, 30000], }); ``` @@ -519,7 +520,7 @@ ctx.curl(url, { ```js ctx.curl(url, { - agent: false + agent: false, }); ``` @@ -529,7 +530,7 @@ ctx.curl(url, { ```js ctx.curl(url, { - httpsAgent: false + httpsAgent: false, }); ``` @@ -540,7 +541,7 @@ ctx.curl(url, { ```js ctx.curl(url, { // 参数必须按照 `user:password` 格式设置 - auth: 'foo:bar' + auth: "foo:bar", }); ``` @@ -551,7 +552,7 @@ ctx.curl(url, { ```js ctx.curl(url, { // 参数必须按照 `user:password` 格式设置 - digestAuth: 'foo:bar' + digestAuth: "foo:bar", }); ``` @@ -561,7 +562,7 @@ ctx.curl(url, { ```js ctx.curl(url, { - followRedirect: true + followRedirect: true, }); ``` @@ -573,7 +574,7 @@ ctx.curl(url, { ctx.curl(url, { followRedirect: true, // 最多自动跳转 5 次 - maxRedirects: 5 + maxRedirects: 5, }); ``` @@ -585,11 +586,11 @@ ctx.curl(url, { ctx.curl(url, { formatRedirectUrl: (from, to) => { // 比如可以在这里修正跳转不正确的 URL - if (to === '//foo/') { - to = '/foo'; + if (to === "//foo/") { + to = "/foo"; } return url.resolve(from, to); - } + }, }); ``` @@ -601,8 +602,8 @@ HttpClient 在请求正式发送之前,会尝试调用 `beforeRequest` 钩子 ctx.curl(url, { beforeRequest: (options) => { // 比如可以在这里设置全局请求 ID,便于日志跟踪 - options.headers['x-request-id'] = uuid.v1(); - } + options.headers["x-request-id"] = uuid.v1(); + }, }); ``` @@ -612,7 +613,7 @@ ctx.curl(url, { ```js const result = await ctx.curl(url, { - streaming: true + streaming: true, }); console.log(result.status, result.data); @@ -621,6 +622,7 @@ ctx.body = result.res; ``` **注意**:如果 res 不是直接传递给 body,那么我们必须消费这个 stream 并且做好 `error` 事件的处理。 + ### `gzip: Boolean` 是否支持 gzip 响应格式,默认为 `false`。开启 gzip 之后,HttpClient 将自动设置 `Accept-Encoding: gzip` 请求头,并且会自动解压带有 `Content-Encoding: gzip` 响应头的数据。 @@ -636,6 +638,7 @@ ctx.curl(url, { 是否开启请求各阶段的时间测量,默认为 `false`。开启 timing 之后,可以通过 `result.res.timing` 拿到这次 HTTP 请求各阶段的时间测量值(单位是毫秒)。通过这些测量值,我们可以非常方便地定位到这次请求最慢的环节发生在哪个阶段。效果类似于Chrome network timing。 timing 各阶段测量值解析: + - queuing:分配 socket 的耗时 - dnslookup:DNS 查询耗时 - connected:socket 三次握手连接成功耗时 @@ -697,34 +700,41 @@ $ http_proxy=http://127.0.0.1:8888 npm run dev ## 常见错误 ### 创建连接超时 + - 异常名称:`ConnectionTimeoutError` - 出现场景:通常是 DNS 查询较慢或者客户端与服务端网络较慢导致。 - 排查建议:适当增大 `timeout` 参数。 ### 服务响应超时 + - 异常名称:`ResponseTimeoutError` - 出现场景:客户端与服务端网络较慢,响应数据较大时发生。 - 排查建议:适当增大 `timeout` 参数。 ### 服务主动断开连接 + - 异常名称:`ResponseError, code: ECONNRESET` - 出现场景:服务端主动断开 socket 连接,导致 HTTP 请求链路异常。 - 排查建议:检查服务端是否发生网络异常。 ### 服务不可达 + - 异常名称:`RequestError, code: ECONNREFUSED, status: -1` - 出现场景:请求的 URL 所属 IP 或端口无法连接。 - 排查建议:确保 IP 或端口设置正确。 ### 域名不存在 + - 异常名称:`RequestError, code: ENOTFOUND, status: -1` - 出现场景:请求的 URL 域名无法通过 DNS 解析。 - 排查建议:确保域名存在,检查 DNS 服务配置。 ### JSON 响应数据格式错误 + - 异常名称:`JSONResponseFormatError` - 出现场景:设置 `dataType=json` 但响应数据不是 JSON 格式时抛出。 - 排查建议:确保服务端返回正确的 JSON 格式数据。 + ## 全局 `request` 和 `response` 事件 在企业应用场景中,常常会有统一 tracer 日志的需求。 @@ -751,7 +761,7 @@ $ http_proxy=http://127.0.0.1:8888 npm run dev 请求发送之前,会触发一个 `request` 事件,允许对请求做拦截。 ```js -app.httpclient.on('request', (req) => { +app.httpclient.on("request", (req) => { req.url; // 请求 URL req.ctx; // 发起这次请求的当前上下文 @@ -764,7 +774,7 @@ app.httpclient.on('request', (req) => { 请求结束之后会触发一个 `response` 事件,这样外部就可以订阅这个事件来打印日志。 ```js -app.httpclient.on('response', (result) => { +app.httpclient.on("response", (result) => { result.res.status; // 响应状态码 result.ctx; // 发起这次请求的当前上下文 result.req; // 对应的 req 对象,即 request 事件里的那个 req @@ -776,6 +786,7 @@ app.httpclient.on('response', (result) => { 完整示例代码可以在 [eggjs/examples/httpclient](https://github.com/eggjs/examples/blob/master/httpclient) 找到。 其他参考链接: + - [urllib](https://github.com/node-modules/urllib) - [httpclient](https://github.com/eggjs/egg/blob/master/lib/core/httpclient.js) - [formstream](https://github.com/node-modules/formstream) diff --git a/site/docs/core/i18n.md b/site/docs/core/i18n.md index ba3f952381..338974de3a 100644 --- a/site/docs/core/i18n.md +++ b/site/docs/core/i18n.md @@ -12,7 +12,7 @@ Default `en-US`. Assume that we want to switch the default language to Simplifie ```js // config/config.default.js exports.i18n = { - defaultLocale: 'zh-CN', + defaultLocale: "zh-CN", }; ``` @@ -31,10 +31,10 @@ If want to modify parameter name of query or cookie ```js // config/config.default.js exports.i18n = { - queryField: 'locale', - cookieField: 'locale', + queryField: "locale", + cookieField: "locale", // Cookie default expired after one year, the unit is ms if set as Number - cookieMaxAge: '1y', + cookieMaxAge: "1y", }; ``` @@ -58,7 +58,7 @@ Example: ```js // config/locale/zh-CN.js module.exports = { - Email: '邮箱', + Email: "邮箱", }; ``` @@ -80,7 +80,7 @@ Use `__` (Alias: `gettext`) function to get the multi-language texts under local Take above multi-language configuration as example: ```js -ctx.__('Email'); +ctx.__("Email"); // zh-CN => 邮箱 // en-US => Email ``` @@ -90,10 +90,10 @@ If texts contain format function like `%s`,`%j`, we can call by the way simila ```js // config/locale/zh-CN.js module.exports = { - 'Welcome back, %s!': '欢迎回来,%s!', + "Welcome back, %s!": "欢迎回来,%s!", }; -ctx.__('Welcome back, %s!', 'Shawn'); +ctx.__("Welcome back, %s!", "Shawn"); // zh-CN => 欢迎回来,Shawn! // en-US => Welcome back, Shawn! ``` @@ -103,10 +103,10 @@ Support array, subscript and placeholder, such as ```js // config/locale/zh-CN.js module.exports = { - 'Hello {0}! My name is {1}.': '你好 {0}! 我的名字叫 {1}。', + "Hello {0}! My name is {1}.": "你好 {0}! 我的名字叫 {1}。", }; -ctx.__('Hello {0}! My name is {1}.', ['foo', 'bar']); +ctx.__("Hello {0}! My name is {1}.", ["foo", "bar"]); // zh-CN => 你好 foo!我的名字叫 bar。 // en-US => Hello foo! My name is bar. ``` diff --git a/site/docs/core/i18n.zh-CN.md b/site/docs/core/i18n.zh-CN.md index e99cee3fc8..be7abbfe6f 100644 --- a/site/docs/core/i18n.zh-CN.md +++ b/site/docs/core/i18n.zh-CN.md @@ -12,7 +12,7 @@ order: 11 ```js // config/config.default.js exports.i18n = { - defaultLocale: 'zh-CN', + defaultLocale: "zh-CN", }; ``` @@ -29,10 +29,10 @@ exports.i18n = { ```js // config/config.default.js exports.i18n = { - queryField: 'locale', - cookieField: 'locale', + queryField: "locale", + cookieField: "locale", // Cookie 默认一年后过期, 如果设置为 Number,则单位为 ms - cookieMaxAge: '1y', + cookieMaxAge: "1y", }; ``` @@ -54,7 +54,7 @@ exports.i18n = { ```js // config/locale/zh-CN.js module.exports = { - Email: '邮箱', + Email: "邮箱", }; ``` @@ -66,6 +66,7 @@ module.exports = { "Email": "邮箱" } ``` + ## 获取多语言文本 我们可以使用 `__`(别名:`gettext`)函数获取 locale 文件夹下面的多语言文本。 @@ -75,7 +76,7 @@ module.exports = { 以上面配置过的多语言为例: ```js -ctx.__('Email'); +ctx.__("Email"); // zh-CN => 邮箱 // en-US => Email ``` @@ -85,10 +86,10 @@ ctx.__('Email'); ```js // config/locale/zh-CN.js module.exports = { - 'Welcome back, %s!': '欢迎回来,%s!', + "Welcome back, %s!": "欢迎回来,%s!", }; -ctx.__('Welcome back, %s!', 'Shawn'); +ctx.__("Welcome back, %s!", "Shawn"); // zh-CN => 欢迎回来,Shawn! // en-US => Welcome back, Shawn! ``` @@ -98,10 +99,10 @@ ctx.__('Welcome back, %s!', 'Shawn'); ```js // config/locale/zh-CN.js module.exports = { - 'Hello {0}! My name is {1}.': '你好 {0}!我的名字叫 {1}。', + "Hello {0}! My name is {1}.": "你好 {0}!我的名字叫 {1}。", }; -ctx.__('Hello {0}! My name is {1}.', ['foo', 'bar']); +ctx.__("Hello {0}! My name is {1}.", ["foo", "bar"]); // zh-CN => 你好 foo!我的名字叫 bar。 // en-US => Hello foo! My name is bar. ``` @@ -113,10 +114,10 @@ class HomeController extends Controller { async index() { const ctx = this.ctx; ctx.body = { - message: ctx.__('Welcome back, %s!', ctx.user.name), + message: ctx.__("Welcome back, %s!", ctx.user.name), // 或者使用 gettext,gettext 是 `__` 函数的别名 // message: ctx.gettext('Welcome back', ctx.user.name) - user: ctx.user + user: ctx.user, }; } } diff --git a/site/docs/core/logger.md b/site/docs/core/logger.md index 492c3fba7e..f773f7ab12 100644 --- a/site/docs/core/logger.md +++ b/site/docs/core/logger.md @@ -27,7 +27,7 @@ Change `dir` in logger: ```js // config/config.${env}.js exports.logger = { - dir: '/path/to/your/custom/log/dir', + dir: "/path/to/your/custom/log/dir", }; ``` @@ -48,9 +48,9 @@ module.exports = (appInfo) => { return { logger: { appLogName: `${appInfo.name}-web.log`, - coreLogName: 'egg-web.log', - agentLogName: 'egg-agent.log', - errorLogName: 'common-error.log', + coreLogName: "egg-web.log", + agentLogName: "egg-agent.log", + errorLogName: "common-error.log", }, }; }; @@ -63,19 +63,19 @@ module.exports = (appInfo) => { It's proper to log details in requests with context logger. The logger will append basics about requests to each log. For example, `[$userId/$ip/$traceId/${cost}ms $method $url]`. ```js -ctx.logger.debug('debug info'); -ctx.logger.info('some request data: %j', ctx.request.body); -ctx.logger.warn('WARNING!!!!'); +ctx.logger.debug("debug info"); +ctx.logger.info("some request data: %j", ctx.request.body); +ctx.logger.warn("WARNING!!!!"); // .error will save information in call stack into errorLog file. // Exceptions must be guaranteed to be Error or object extended from Error, which offers a trace of what functions were called. -ctx.logger.error(new Error('whoops')); +ctx.logger.error(new Error("whoops")); ``` For developers who create frameworks or plugins, `ctx.coreLogger` is another option in Context Logger. ```js -ctx.coreLogger.info('info'); +ctx.coreLogger.info("info"); ``` ### App Logger @@ -85,9 +85,9 @@ For developers who want to know more details about dispatch in Egg, they can eas ```js // app.js module.exports = (app) => { - app.logger.debug('debug info'); - app.logger.info('Latency: %d ms', Date.now() - start); - app.logger.warn('warning!'); + app.logger.debug("debug info"); + app.logger.info("Latency: %d ms", Date.now() - start); + app.logger.warn("warning!"); app.logger.error(someErrorObj); }; @@ -98,7 +98,7 @@ module.exports = (app) => { ```js // app.js module.exports = (app) => { - app.coreLogger.info('Latency: %d ms', Date.now() - start); + app.coreLogger.info("Latency: %d ms", Date.now() - start); }; ``` @@ -109,9 +109,9 @@ Agent also supports `agent.coreLogger` as the same feature to context and app ab ```js // agent.js module.exports = (agent) => { - agent.logger.debug('debug info'); - agent.logger.info('Latency: %d ms', Date.now() - start); - agent.logger.warn('warning!'); + agent.logger.debug("debug info"); + agent.logger.info("Latency: %d ms", Date.now() - start); + agent.logger.warn("warning!"); agent.logger.error(someErrorObj); }; @@ -126,7 +126,7 @@ The default encoding setting(`utf-8`) can be changed via `encoding` in config: ```js // config/config.${env}.js exports.logger = { - encoding: 'gbk', + encoding: "gbk", }; ``` @@ -154,7 +154,7 @@ If you want to change logger's default output level, modify in the config as fol ```js // config/config.${env}.js exports.logger = { - level: 'DEBUG', // logs in all level will be written into files + level: "DEBUG", // logs in all level will be written into files }; ``` @@ -163,7 +163,7 @@ Stop writing logs in all levels: ```js // config/config.${env}.js exports.logger = { - level: 'NONE', + level: "NONE", }; ``` @@ -174,7 +174,7 @@ To avoid some plugin's DEBUG logs printing in the production environment causing ```js // config/config.prod.js exports.logger = { - level: 'DEBUG', + level: "DEBUG", allowDebugAtProd: true, }; ``` @@ -192,7 +192,7 @@ Print logs in all levels: ```js // config/config.${env}.js exports.logger = { - consoleLevel: 'DEBUG', + consoleLevel: "DEBUG", }; ``` @@ -201,7 +201,7 @@ Stop printing logs in all levels: ```js // config/config.${env}.js exports.logger = { - consoleLevel: 'NONE', + consoleLevel: "NONE", }; ``` @@ -224,13 +224,13 @@ The logger you create can be declared in config: ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { customLogger: { xxLogger: { - file: path.join(appInfo.root, 'logs/xx.log'), + file: path.join(appInfo.root, "logs/xx.log"), }, }, }; @@ -243,13 +243,13 @@ Now, you can get loggers via `app.getLogger('xxLogger')` or `ctx.getLogger('xxLo ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { customLogger: { xxLogger: { - file: path.join(appInfo.root, 'logs/xx.log'), + file: path.join(appInfo.root, "logs/xx.log"), formatter(meta) { return `[${meta.date}] ${meta.message}`; }, @@ -272,9 +272,9 @@ Transport can be considered as a tunnel to transfer data in Egg. A logger contai For concrete scenario, we take `common-error.log` as an example, which not only printed into files, but also sent to another remote service. At first, we can create a new transport for sending logs to remote: ```js -const co = require('co'); -const util = require('util'); -const Transport = require('egg-logger').Transport; +const co = require("co"); +const util = require("util"); +const Transport = require("egg-logger").Transport; class RemoteErrorTransport extends Transport { // Create log() to upload logs @@ -282,30 +282,22 @@ class RemoteErrorTransport extends Transport { let log; if (args[0] instanceof Error) { const err = args[0]; - log = util.format( - '%s: %s\n%s\npid: %s\n', - err.name, - err.message, - err.stack, - process.pid, - ); + log = util.format("%s: %s\n%s\npid: %s\n", err.name, err.message, err.stack, process.pid); } else { log = util.format(...args); } this.options.app - .curl('http://url/to/remote/error/log/service/logs', { + .curl("http://url/to/remote/error/log/service/logs", { data: log, - method: 'POST', + method: "POST", }) .catch(console.error); } } // Transport attached to errorLogger in app.js, makes logs sync to it once those are created. -app - .getLogger('errorLogger') - .set('remote', new RemoteErrorTransport({ level: 'ERROR', app })); +app.getLogger("errorLogger").set("remote", new RemoteErrorTransport({ level: "ERROR", app })); ``` Performance is what we always consider as important part in our services so that logs will firstly be written into memory and transferred to remote later. @@ -324,14 +316,12 @@ The log file also can be cut into ones by size. For example, Egg will process `e ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { logrotator: { - filesRotateBySize: [ - path.join(appInfo.root, 'logs', appInfo.name, 'egg-web.log'), - ], + filesRotateBySize: [path.join(appInfo.root, "logs", appInfo.name, "egg-web.log")], maxFileSize: 2 * 1024 * 1024 * 1024, }, }; @@ -348,14 +338,12 @@ For example, we need to cut `common-error.log` by hour just like following imple ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { logrotator: { - filesRotateByHour: [ - path.join(appInfo.root, 'logs', appInfo.name, 'common-error.log'), - ], + filesRotateByHour: [path.join(appInfo.root, "logs", appInfo.name, "common-error.log")], }, }; }; diff --git a/site/docs/core/logger.zh-CN.md b/site/docs/core/logger.zh-CN.md index ecd68e4084..23c28163b7 100644 --- a/site/docs/core/logger.zh-CN.md +++ b/site/docs/core/logger.zh-CN.md @@ -27,7 +27,7 @@ order: 4 ```js // config/config.${env}.js exports.logger = { - dir: '/path/to/your/custom/log/dir', + dir: "/path/to/your/custom/log/dir", }; ``` @@ -44,13 +44,13 @@ exports.logger = { ```js // config/config.${env}.js -module.exports = appInfo => { +module.exports = (appInfo) => { return { logger: { appLogName: `${appInfo.name}-web.log`, - coreLogName: 'egg-web.log', - agentLogName: 'egg-agent.log', - errorLogName: 'common-error.log', + coreLogName: "egg-web.log", + agentLogName: "egg-agent.log", + errorLogName: "common-error.log", }, }; }; @@ -65,13 +65,13 @@ module.exports = appInfo => { 每行日志会自动记录当前请求的一些基本信息,如 `[$userId/$ip/$traceId/${cost}ms $method $url]`。 ```js -ctx.logger.debug('debug info'); -ctx.logger.info('some request data: %j', ctx.request.body); -ctx.logger.warn('警告!'); +ctx.logger.debug("debug info"); +ctx.logger.info("some request data: %j", ctx.request.body); +ctx.logger.warn("警告!"); // 错误日志记录,直接会将错误日志的完整堆栈信息记录下来,并且输出到 errorLog 中 // 为了保证异常可追踪,必须保证所有抛出的异常都是 Error 类型,因为只有 Error 类型才会带上堆栈信息,定位到问题。 -ctx.logger.error(new Error('whoops')); +ctx.logger.error(new Error("whoops")); ``` 对于框架开发者和插件开发者,还可以使用 `ctx.coreLogger`。 @@ -79,7 +79,7 @@ ctx.logger.error(new Error('whoops')); 例如: ```js -ctx.coreLogger.info('info'); +ctx.coreLogger.info("info"); ``` ### App Logger @@ -88,10 +88,10 @@ ctx.coreLogger.info('info'); ```js // app.js -module.exports = app => { - app.logger.debug('debug info'); - app.logger.info('启动耗时 %d ms', Date.now() - start); - app.logger.warn('警告!'); +module.exports = (app) => { + app.logger.debug("debug info"); + app.logger.info("启动耗时 %d ms", Date.now() - start); + app.logger.warn("警告!"); app.logger.error(someErrorObj); }; @@ -101,8 +101,8 @@ module.exports = app => { ```js // app.js -module.exports = app => { - app.coreLogger.info('启动耗时 %d ms', Date.now() - start); +module.exports = (app) => { + app.coreLogger.info("启动耗时 %d ms", Date.now() - start); }; ``` @@ -112,16 +112,17 @@ module.exports = app => { ```js // agent.js -module.exports = agent => { - agent.logger.debug('debug info'); - agent.logger.info('启动耗时 %d ms', Date.now() - start); - agent.logger.warn('警告!'); +module.exports = (agent) => { + agent.logger.debug("debug info"); + agent.logger.info("启动耗时 %d ms", Date.now() - start); + agent.logger.warn("警告!"); agent.logger.error(someErrorObj); }; ``` 如需详细了解 Agent 进程,请参考[多进程模型](./cluster-and-ipc.md)。 + ## 日志文件编码 默认编码为 `utf-8`,可通过下面的方式进行覆盖: @@ -129,7 +130,7 @@ module.exports = agent => { ```js // config/config.${env}.js exports.logger = { - encoding: 'gbk', + encoding: "gbk", }; ``` @@ -161,7 +162,7 @@ exports.logger = { ```js // config/config.${env}.js exports.logger = { - level: 'DEBUG', + level: "DEBUG", }; ``` @@ -170,7 +171,7 @@ exports.logger = { ```js // config/config.${env}.js exports.logger = { - level: 'NONE', + level: "NONE", }; ``` @@ -181,7 +182,7 @@ exports.logger = { ```js // config/config.prod.js exports.logger = { - level: 'DEBUG', + level: "DEBUG", allowDebugAtProd: true, }; ``` @@ -197,7 +198,7 @@ exports.logger = { ```js // config/config.${env}.js exports.logger = { - consoleLevel: 'DEBUG', + consoleLevel: "DEBUG", }; ``` @@ -206,7 +207,7 @@ exports.logger = { ```js // config/config.${env}.js exports.logger = { - consoleLevel: 'NONE', + consoleLevel: "NONE", }; ``` @@ -218,6 +219,7 @@ exports.logger = { disableConsoleAfterReady: false, }; ``` + ## 自定义日志 ### 增加自定义日志 @@ -228,15 +230,15 @@ exports.logger = { ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); -module.exports = appInfo => { +module.exports = (appInfo) => { return { customLogger: { xxLogger: { - file: path.join(appInfo.root, 'logs/xx.log') - } - } + file: path.join(appInfo.root, "logs/xx.log"), + }, + }, }; }; ``` @@ -247,21 +249,21 @@ module.exports = appInfo => { ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); -module.exports = appInfo => { +module.exports = (appInfo) => { return { customLogger: { xxLogger: { - file: path.join(appInfo.root, 'logs/xx.log'), + file: path.join(appInfo.root, "logs/xx.log"), formatter(meta) { return `[${meta.date}] ${meta.message}`; }, contextFormatter(meta) { return `[${meta.date}] [${meta.ctx.method} ${meta.ctx.url}] ${meta.message}`; - } - } - } + }, + }, + }, }; }; ``` @@ -273,8 +275,8 @@ module.exports = appInfo => { 首先,我们定义一个日志的传输通道(transport),该通道代表第三方日志服务。 ```js -const util = require('util'); -const Transport = require('egg-logger').Transport; +const util = require("util"); +const Transport = require("egg-logger").Transport; class RemoteErrorTransport extends Transport { // 定义 log 方法。在此方法中,将日志上报给远端服务。 @@ -282,30 +284,26 @@ class RemoteErrorTransport extends Transport { let log; if (args[0] instanceof Error) { const err = args[0]; - log = util.format( - '%s: %s\n%s\npid: %s\n', - err.name, - err.message, - err.stack, - process.pid - ); + log = util.format("%s: %s\n%s\npid: %s\n", err.name, err.message, err.stack, process.pid); } else { log = util.format(...args); } - this.options.app.curl('http://url/to/remote/error/log/service/logs', { - data: log, - method: 'POST' - }) - .catch(console.error); + this.options.app + .curl("http://url/to/remote/error/log/service/logs", { + data: log, + method: "POST", + }) + .catch(console.error); } } // 在 app.js 中给 errorLogger 添加 transport,这样每条日志就会同时打印到这个 transport。 -app.getLogger('errorLogger').set('remote', new RemoteErrorTransport({ level: 'ERROR', app })); +app.getLogger("errorLogger").set("remote", new RemoteErrorTransport({ level: "ERROR", app })); ``` 上述代码示例中,虽然比较简单,但是在实际使用时需要考虑性能问题。通常采取先暂存至内存,再定时上传的策略,以此优化性能。 + ## 日志切割 企业级日志一个最常见的需求之一是对日志进行自动切割,以方便管理。框架对日志切割的支持由 [egg-logrotator](https://github.com/eggjs/egg-logrotator) 插件提供。 @@ -324,14 +322,12 @@ app.getLogger('errorLogger').set('remote', new RemoteErrorTransport({ level: 'ER ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { logrotator: { - filesRotateBySize: [ - path.join(appInfo.root, 'logs', appInfo.name, 'egg-web.log'), - ], + filesRotateBySize: [path.join(appInfo.root, "logs", appInfo.name, "egg-web.log")], maxFileSize: 2 * 1024 * 1024 * 1024, }, }; @@ -348,14 +344,12 @@ module.exports = (appInfo) => { ```js // config/config.${env}.js -const path = require('path'); +const path = require("path"); module.exports = (appInfo) => { return { logrotator: { - filesRotateByHour: [ - path.join(appInfo.root, 'logs', appInfo.name, 'common-error.log'), - ], + filesRotateByHour: [path.join(appInfo.root, "logs", appInfo.name, "common-error.log")], }, }; }; diff --git a/site/docs/core/security.md b/site/docs/core/security.md index b66bf21139..d848cd4578 100644 --- a/site/docs/core/security.md +++ b/site/docs/core/security.md @@ -49,7 +49,7 @@ For example, just open csp when path contains `/example`, you can configure with ```js exports.security = { csp: { - match: '/example', + match: "/example", policy: { //... }, @@ -64,7 +64,7 @@ For example, just disable xframe when path contains `/example` while our pages c ```js exports.security = { csp: { - ignore: '/example', + ignore: "/example", xframe: { //... }, @@ -189,7 +189,7 @@ Note shtml uses a strict whitelisting mechanism, not only filter out the XSS ris For example, tag `HTML` is not in the whitelist. ```js -const html = ''; +const html = ""; // html { @@ -279,11 +279,7 @@ The framework combines these precautions to provide a configurable CSRF preventi In synchronous rendering the page, you should add a parameter name called `_csrf` in the form's submit url, the value is `ctx.csrf`, when user submitting this form , CSRF token will be submitted: ```html -
+ title: file:
@@ -296,8 +292,8 @@ Fields that pass the CSRF token can be changed in the configuration: module.exports = { security: { csrf: { - queryName: '_csrf', // CSRF token parameter name passed through query, default is _csrf - bodyName: '_csrf', // CSRF token parameter name passed through body, default is _csrf + queryName: "_csrf", // CSRF token parameter name passed through query, default is _csrf + bodyName: "_csrf", // CSRF token parameter name passed through body, default is _csrf }, }, }; @@ -312,7 +308,7 @@ In the default configuration, the token is set in the Cookie, which can be fetch In jQuery: ```js -var csrftoken = Cookies.get('csrfToken'); +var csrftoken = Cookies.get("csrfToken"); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection @@ -321,7 +317,7 @@ function csrfSafeMethod(method) { $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { - xhr.setRequestHeader('x-csrf-token', csrftoken); + xhr.setRequestHeader("x-csrf-token", csrftoken); } }, }); @@ -334,7 +330,7 @@ The fields that pass the CSRF token through the header can also be changed in th module.exports = { security: { csrf: { - headerName: 'x-csrf-token', // CSRF token passed through header, default is x-csrf-token + headerName: "x-csrf-token", // CSRF token passed through header, default is x-csrf-token }, }, }; @@ -350,8 +346,8 @@ module.exports = { security: { csrf: { useSession: true, // default is false,if set to true , it will store csrf token in Session - cookieName: 'csrfToken', // Field in Cookie , default is csrfToken - sessionName: 'csrfToken', // Filed in Session , default is csrfToken + cookieName: "csrfToken", // Field in Cookie , default is csrfToken + sessionName: "csrfToken", // Filed in Session , default is csrfToken }, }, }; @@ -400,15 +396,15 @@ exports.login = async function (ctx) { Below, we implement a simple TRACE support server based on Koa: ```js -var koa = require('koa'); +var koa = require("koa"); var app = koa(); app.use(async function (ctx, next) { - ctx.cookies.set('a', 1, { httpOnly: true }); - if (ctx.method === 'TRACE') { - var body = ''; + ctx.cookies.set("a", 1, { httpOnly: true }); + if (ctx.method === "TRACE") { + var body = ""; for (header in ctx.headers) { - body += header + ': ' + ctx.headers[header] + '\r\n'; + body += header + ": " + ctx.headers[header] + "\r\n"; } ctx.body = body; } @@ -493,7 +489,7 @@ You need to do the following configuration in the application configuration file ```js // config/config.default.js exports.security = { - domainWhiteList: ['.domain.com'], // security domain while list, start with . + domainWhiteList: [".domain.com"], // security domain while list, start with . }; ``` @@ -635,13 +631,13 @@ Calling the `safeCurl` method directly does not have any effect. It also needs t exports.security = { ssrf: { ipBlackList: [ - '10.0.0.0/8', // support CIDR subnet - '0.0.0.0/32', - '127.0.0.1', // support specific IP address + "10.0.0.0/8", // support CIDR subnet + "0.0.0.0/32", + "127.0.0.1", // support specific IP address ], // ipBlackList does not take effect when checkAddress is configured checkAddress(ip) { - return ip !== '127.0.0.1'; + return ip !== "127.0.0.1"; }, }, }; @@ -671,7 +667,6 @@ For sites that do not open HTTPS, this function can be limited to preventing ISP ## Revert CVE - In the security fixes of node.js, there may be breaking changes. For example, in version 18.9.1, a security vulnerability was fixed, which caused some encryption-related code to not function properly. To address this issue, we provide a revert parameter, which is converted to the --security-revert parameter at startup, allowing the bypassing of the CVE fix. ```json @@ -682,7 +677,7 @@ In the security fixes of node.js, there may be breaking changes. For example, in // One is to use a string directly, specifying a CVE "revert": "CVE-2023-46809", // The other is to use an array of strings, allowing the specification of multiple CVEs - "revert": [ "CVE-2023-46809" ] + "revert": ["CVE-2023-46809"] } } ``` diff --git a/site/docs/core/security.zh-CN.md b/site/docs/core/security.zh-CN.md index 74796e06ff..193666da7c 100644 --- a/site/docs/core/security.zh-CN.md +++ b/site/docs/core/security.zh-CN.md @@ -47,7 +47,7 @@ exports.security = { ```js exports.security = { csp: { - match: '/example', + match: "/example", policy: { // ... }, @@ -60,7 +60,7 @@ exports.security = { ```js exports.security = { csp: { - ignore: '/example', + ignore: "/example", xframe: { // ... }, @@ -82,9 +82,10 @@ exports.security = { 下面将针对具体的场景,来讲解如何使用框架提供的安全方案进行 Web 安全防范。 --- + ## 安全威胁 XSS 的防范 -[XSS](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS))(Cross-Site Scripting,跨站脚本攻击)攻击是最常见的 Web 攻击,其重点是“跨域”和“客户端执行”。 +[XSS]()(Cross-Site Scripting,跨站脚本攻击)攻击是最常见的 Web 攻击,其重点是“跨域”和“客户端执行”。 XSS 攻击一般分为两类: @@ -174,7 +175,7 @@ const value = `google