## 1. Project Overview & Quickstart (midwayjs/midway)

## File: README.md

[English](./README.en-US.md) | 简体中文


## 资源

- [2022 夏季 mini 直面会](https://www.bilibili.com/video/BV1QB4y1q7Qs)
- [2022 冬季直面会](https://www.bilibili.com/video/BV1W44y1s7dj?spm_id_from=333.999.0.0)
- [3.x beta 功能预览](https://www.bilibili.com/video/BV1aL4y1p7oA?from=search&seid=8235946720906913847&spm_id_from=333.337.0.0)
- [2021 秋季直面会](https://www.bilibili.com/video/BV1Ng411T76f?from=search&seid=8235946720906913847&spm_id_from=333.337.0.0)
- [2021 夏季直面会](https://www.bilibili.com/video/BV1nF411a7sr?from=search&seid=8235946720906913847&spm_id_from=333.337.0.0)
- [v2 示例教程](https://www.bilibili.com/video/BV1254y1E73m?from=search&seid=8235946720906913847&spm_id_from=333.337.0.0)
- [2.0 发布会回放](https://www.bilibili.com/video/BV17A411T7Md)[《2.0 发布会文章》](https://zhuanlan.zhihu.com/p/355768659)

## 特性

- 🐘 **全功能**：支持 Web 应用/Serverless/FaaS/微服务/小程序后端等多种场景，基于装饰器和依赖注入开发企业级应用
- 🐦 **前端集成**：全新的云端一体应用研发体验，零 API 调用，使用 "React Hooks " 风格一体研发
- 🐴 **跨平台**：支持部署至普通 Server 或 Serverless/FaaS 环境
- 🐶 **扩展**：组件化扩展能力，另外支持使用 Koa/Express/Egg.js 生态插件
- 🐂 **示例**: 官方提供多种场景的示例代码，方便开发者快速上手
- 🛡 TypeScript 全面支持

## 描述

Midway 是一个适用于构建 Serverless 服务，传统应用、微服务，小程序后端的 Node.js 框架。

Midway 可以使用 Koa，Express 或 Egg.js 作为基础 Web 框架。它还提供了独立使用的基本解决方案，例如 Socket.io，GRPC，Dubbo.js 和 RabbitMQ 等。

此外，Midway 也适用于前端/全栈开发人员的 Node.js 无服务器框架。构建下一个十年的应用程序。可在 AWS，阿里云，腾讯云和传统 VM /容器上运行。与 React 和 Vue 轻松集成。 🌈

## Demo

### 使用装饰器开发 Web 应用

```ts
import { Controller, Get, Provide } from '@midwayjs/decorator';

@Provide()
@Controller('/')
export class HomeController {

  @Get('/')
  async home() {
    return `Welcome to midwayjs!`;
  }
}
```

### 使用函数开发全栈应用

> 后端代码
> src/apis/lambda/index.ts

```typescript
import {
  Api,
  Get,
  Query,
  useContext,
} from '@midwayjs/hooks';

export default Api(
  Get(),
  Query<{
    page: string;
    limit: string;
  }>(),
  async () => {
    const ctx = useContext();
    return {
      page: ctx.query.page,
      limit: ctx.query.limit,
    };
  }
);
```

> 前端调用
> src/page/index.tsx

```typescript
import getArticles from './api';
const response = await getArticles({
  query: { page: '0', limit: '10' },
});
console.log(response); // { page: '0', limit: '10' }
```

> 手动调用

```typescript
fetch('/api/articles?page=0&limit=10')
  .then((res) => res.json())
  .then((res) => console.log(res)); // { page: '0', limit: '10' }
```

## 快速上手

```bash
$ npm -v

## 选择模版
$ npm init midway

## 进入项目路径
cd my_midway_app && npm run dev
```

## 文档和社区

- [官网](https://midwayjs.org)
- [备用官网](https://beta.midwayjs.org)


## 社区优秀示例展示

**1、Cool-Admin - 一个很酷的后台权限管理框架**



- 官网：https://cool-js.com/



## VSC Plugin



## 答疑

群里会有热心的朋友，也会有新版本发布推送。



## 贡献

<a href="https://github.com/midwayjs/midway/graphs/contributors">
  
</a>

请告知我们可以为你做些什么，不过在此之前，请检查一下是否有 [已经存在的Bug或者意见](https://github.com/midwayjs/midway/issues)。

如果你是一个代码贡献者，请参考代码贡献规范。

## 谁在使用


你也想加 Logo ？可以点击 [这里](https://github.com/midwayjs/midway/issues/898) 添加。

## License

我们的代码使用 [MIT](https://github.com/midwayjs/midway/blob/master/LICENSE) 协议，请放心使用。

[](https://app.fossa.com/projects/git%2Bgithub.com%2Fmidwayjs%2Fmidway?ref=badge_large)

---

## File: benchmark/readme.md

# Benchmark

you can run benchmark here for midway framework.

```bash
$ ./ready.sh
$ node index
```

result like this

```text
Waiting for Midway 3 with request context to initialize...
Running benchmark on Midway 3 with request context...
Midway 3 with request context QPS:  2374.4
Waiting for Midway 3 with async hooks to initialize...
Running benchmark on Midway 3 with async hooks...
Midway 3 with async hooks QPS:  2495.81
```

---

## File: packages/ws/README.md

# midway framework for WebSocket

[](http://packagequality.com/#?package=midway-web)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/web-koa/README.md

# midway for koa

[](http://packagequality.com/#?package=@midwayjs/koa)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/web-express/README.md

# midway for express

[](http://packagequality.com/#?package=@midwayjs/express)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/web/README.md

# @midwayjs/web

[](http://packagequality.com/#?package=@midwayjs/web)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/view-nunjucks/README.md

# midway-view-nunjucks

[](http://packagequality.com/#?package=@midwayjs/view-nunjucks)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/view-ejs/README.md

# midway-view-ejs

[](http://packagequality.com/#?package=@midwayjs/view-ejs)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/view/README.md

# midway-view

Base view component for midway.

## Install

@midwayjs/view don't have build-in view engine, So you should choose a template engine like ejs, and install `@midwayjs/view-ejs`.
View component will be auto install and enable by import `view-ejs`.

```bash
$ npm i @midwayjs/view-ejs --save
```

## Usage

First, import component in `src/configuration.ts`.

```typescript
import { Configuration } from '@midwayjs/core';
import * as view from '@midwayjs/view-ejs';
import { join } from 'path'

@Configuration({
  imports: [
    // ...
    view
  ],
  importConfigs: [
    join(__dirname, 'config')
  ]
})
export class ContainerLifeCycle {
}
```

Configure the mapping, the file with `.ejs` extension will be rendered by ejs.

```typescript
// src/config/config.default.ts
export const view = {
  defaultViewEngine: 'ejs',
  mapping: {
    '.ejs': 'ejs',
  },
};

// ejs config
export const ejs = {};
```

In controller, you can call `ctx.render`.

```typescript
import { Inject, Provide } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';

@Controller('/')
export class HomeController {

  @Inject()
  ctx: Context;

  @Get('/')
  async render(){
    await this.ctx.render('hello.ejs', {
      data: 'world',
    });
  }
}
```

## Use multiple view engine

@midwayjs/view support multiple view engine, so you can use more than one template engine in one application.

If you want add another template engine like nunjucks, then you can add @midwayjs/view-nunjucks component.

Configure the plugin and mapping

```typescript
// src/config/config.default.ts
export const view = {
  mapping: {
    '.ejs': 'ejs',
    '.nj': 'nunjucks',
  },
};
```
You can simply render the file with .nj extension.

```typescript
await this.ctx.render('user.nj');
```

## Write a view engine

Create a view engine class first, and implement render and renderString, if the template engine don't support, just throw an error.

```typescript
// lib/view.ts
import { Provide } from '@midwayjs/core';

@Provide()
export class MyView {

  @Config('xxxx')
  viewConfig;

  async render(fullpath, locals) {
    return myengine.render(fullpath, locals);
  }

  async renderString() { throw new Error('not implement'); }
};
```

These methods receive three arguments, `renderString` will pass tpl as the first argument instead of name in `render`.

`render(name, locals, viewOptions)`

- name: the file path that can resolve from root (`/view` by default)
- locals: data used by template
- viewOptions: the view options for each render, it can override the view default config in `config/config.default.js`. Plugin should implement it if it has config.
  When you implement view engine, you will receive this options from `render`, the options contain:
  - root: it will resolve the name to full path, but seperating root and name in viewOptions.
  - name: the original name when call render
  - locals: the original locals when call render

`renderString(tpl, locals, viewOptions)`

- tpl: the template string instead of the file, using in `renderString`
- locals: same as `render`
- viewOptions: same as `render`

### Register

After define a view engine, you can register it.

```typescript
// src/configuration.ts
import { Configuration, Inject, Provide } from '@midwayjs/core';
import * as koa from '@midwayjs/koa';
import * as view from '@midwayjs/view';
import { MyView } from './lib/my';

@Configuration({
  imports: [koa, view],
  importConfigs: [join(__dirname, 'config')]
})
export class AutoConfiguration {

  @Inject()
  viewManager: view.ViewManager;

  async onReady(){
    this.viewManager.use('ejs', MyView);
  }
}

```

You can define a view engine name, normally it's a template name.

## Configuration

### Root

Root is `${appDir}/view` by default, but you can define multiple directory.

```typescript
export default appInfo => {
  const appDir = appInfo.appDir;
  return {
    view: {
      rootDir: {
        default: `${appDir}/view`,
        anotherDir: `${appDir}/view2`
      }
    }
  }
}
```

### defaultExtension

When render a file, you should specify a extension that let @midway/view know which engine you want to use. However you can define `defaultExtension` without write the extension.

```typescript
// src/config/config.default.ts
export const view = {
  defaultExtension: '.html',
};

// controller
import { Inject, Provide } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';

@Controller('/')
export class HomeController {

  @Inject()
  ctx: Context;

  @Get('/')
  async render(){
    // render user.html
    await this.ctx.render('user');
  }
}
```

### viewEngine and defaultViewEngine

If you are using `renderString`, you should specify viewEngine in view config, see example above.

However, you can define `defaultViewEngine` without set each time.

```js
// config/config.default.js
export const view = {
  defaultViewEngine: 'ejs',
};
```


## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

---

## File: packages/validate/README.md

# midway validate module

[](http://packagequality.com/#?package=@midwayjs/validate)
[](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)

## 2. Official Technical Reference & Guides (midwayjs/midwayjs.github.io)

## File: README.md

# midway site

```bash
npm i
# dev site in docs
npm run dev
# run build
npm run deploy
git commit -m "docs:add site"
git push origin master
```

---

## File: docs/en/index.md

English Document is not ready.

Please see docuemnt with `?translate=en` parameter.

Like: [introduction](https://www.yuque.com/midwayjs/midway_v2/introduction?translate=en)

---

## File: docs/README.md

---
home: false
nav: false
actionText: 快速上手 →
actionLink: /guide
footer: Copyright © 2018-present MidwayJs
pageClass: home-class
---

  
    
      
      
        <nav>
          [使用文档](https://www.yuque.com/midwayjs/midway_v2)
          [示例库](http://demo.midwayjs.org/)
          [API](/api-reference/index.html)
          [Node 地下铁 Club](https://subway.midwayjs.org)
          [备用文档](start_app.html)
        </nav>
        
      
    
  
  
    
      
        一个面向未来的
        云端一体 Node.js 框架
        Midway 是一个适用于构建 Serverless 服务，传统应用、微服务，小程序后端的 Node.js 框架
      
      
        
          <a class="home-top-button button view" href="https://www.yuque.com/midwayjs/midway_v2">访问文档</a>
          
          
          
        
        <a class="home-top-button button white" href="https://github.com/midwayjs/midway">源码</a>
      
    
  
  
    
      Midway Serverless 2.0
      全新的一体化方案
      全新的 Serverless 测试方案
      业界首创的全栈开发方式
      我们的发布会已结束，可以扫描右侧二维码观看回放
      
        
          
          bilibili 前端圈（直播回放）
        
         
          
          Node.js 地下铁
        
      
    
  
  
    
      不论你在寻求何种解决方案，
      Midway 总能提供给你最适合的那一个
      
      
      
      <a class="home-solution-more button" href="http://demo.midwayjs.org/">查看所有解决方案</a>
      
        
          <a class="ad-middle-button button white" href="http://d2forum.alibaba-inc.com/" target="_blank">点击报名</a>
        
        
          <a class="ad-middle-button button white" href="https://mudu.tv/watch/7560584">了解更多</a>
        
      
    
  
  
    
      为什么选择 Midway?
      
        Serverless 应用云端一体
        Midway 不仅提供了和各个前端框架结合的能力，在传统的开发基础上，更增加了一体化研发模式，让前端业务能够更自如的调用 Node.js 代码，开发的更快更简单。
        
      
      
        代码复用和组件化能力
        Midway  不仅抽象出了满足不同场景的上层框架，也提供了跨场景复用的组件化能力，甚至还提供了业务代码的复用组件 ，让业务代码可以轻量化的拷贝和分享到不同的场景应用。
        
      
      
        一份代码，多场景部署
        Midway 提供了一套完整的解决方案，只需要写一次代码，就可以自动构建出适合于传统应用 ，微服务，乃至 Serverless 环境的代码包 ，方便用户移植程序到不同的部署环境。
        
      
      
        高并发业务稳定高效
        Midway 在 阿里集团内部已经普遍使用，经过了多次大促的洗礼，整个框架已经非常高效和稳定。默认情况下， Midway 在 Web Application 开发时提供了非常多的内置能力，用户无需再去查询其他能力。
        
      
    
  
  
    
      加入我们
      MidwayJs 是一个开源品牌，旗下的产品都为 MIT 协议，欢迎各位提交代码 ，一起共建 Node.js 生态。
      
    
  
  
    
      
        © 2021 ~ ∞ Midwayjs@Serverless
        <a class="link" href="https://github.com/midwayjs/midway">Github</a>
        <a class="link" href="https://github.com/midwayjs/midway/issues">Issue</a>
        <a class="link" href="https://www.yuque.com/midwayjs/topics">Help</a>
        <a class="link" href="http://demo.midwayjs.org/">Gallery</a>
      
      <a class="bottom-logo"></a>
      
        <a class="link" href="https://github.com/midwayjs/pandora">Pandora</a>
        <a class="link" href="https://github.com/midwayjs/injection">Injection</a>
        <a class="link" href="https://github.com/midwayjs/sandbox-docker">Sandbox</a>
        <a class="link" href="https://ice.work/">ICE</a>
      
    
  
  <script type="text/javascript">document.write(unescape("%3Cspan id='cnzz_stat_icon_1279723477'%3E%3C/span%3E%3Cscript src='https://v1.cnzz.com/z_stat.php%3Fid%3D1279723477' type='text/javascript'%3E%3C/script%3E"));</script>

<script>
let topWallList = [
  { cover: '//gw.alicdn.com/imgextra/i4/19999999999999/O1CN01PEPPo02NjasvUe8cc_!!19999999999999-2-tps.png' }, // react
  { cover: '//gw.alicdn.com/tfs/TB1Cdu2UYr1gK0jSZFDXXb9yVXa-1200-669.png' }, // vue
  { cover: '//gw.alicdn.com/tfs/TB18DKdjCR26e4jSZFEXXbwuXXa-1200-669.png' }, // rax
  { cover: '//gw.alicdn.com/tfs/TB11mzgg0Tfau8jSZFwXXX1mVXa-1200-669.png' }, // tablestore
  { cover: '//gw.alicdn.com/imgextra/i3/19999999999999/O1CN01HLo3Pi2NjasqFIZbi_!!19999999999999-2-tps.png' }, // koa
  { cover: '//gw.alicdn.com/imgextra/i2/19999999999999/O1CN01LggSYp2NjassPrZeZ_!!19999999999999-2-tps.png' }, // ice
  { cover: '//gw.alicdn.com/tfs/TB1l2LaU1L2gK0jSZFmXXc7iXXa-1200-669.png' }, // hexo
  { cover: '//gw.alicdn.com/tfs/TB12AhMjcVl614jSZKPXXaGjpXa-1200-669.png' }, // express
  { cover: '//gw.alicdn.com/tfs/TB1NtHPh5pE_u4jSZKbXXbCUVXa-1200-669.png' }, // egg
  { cover: '//gw.alicdn.com/tfs/TB1bonEgsieb18jSZFvXXaI3FXa-1200-669.png' }, // dingtalk
  // { cover: '//gw.alicdn.com/tfs/TB1oq7GfxvbeK8jSZPfXXariXXa-1200-669.png' }, // covid19
  { cover: '//gw.alicdn.com/tfs/TB1Fh51U.Y1gK0jSZFMXXaWcVXa-1200-669.png' }, // antd
  { cover: '//gw.alicdn.com/tfs/TB1Ro.miMgP7K4jSZFqXXamhVXa-1200-669.png' }, // typeorm
  { cover: '//gw.alicdn.com/imgextra/i1/19999999999999/O1CN01FDOJdG2NjasvEbjxX_!!19999999999999-2-tps.png' }, // sequelize
  { cover: '//gw.alicdn.com/tfs/TB1MM_aU8r0gK0jSZFnXXbRRXXa-1200-669.png' }, // img
  { cover: '//gw.alicdn.com/tfs/TB1Fuy3UYr1gK0jSZFDXXb9yVXa-1200-669.png' }, // ssr
];
const solutionList = [
  { title: 'Serverless HTTP API' },
  { title: 'Serverless 定时器' },
  { title: 'Serverless 事件触发' },
  { title: 'RESTFul API' },
  { title: 'WebSocket' },
  { title: '微服务' },
  { title: 'React 一体化' },
  { title: 'Vue 一体化' },
  { title: 'ICE 一体化' },
  { title: 'Rax 一体化' },
];
topWallList = topWallList.sort(() => {
  return Math.random() - 0.5;
});
const topWallEle = document.getElementById('top-wall');
const solutionContainer = document.getElementById('home-solution-container');
const topWallItemList = [];
// render top wall
const lastLineIndex = (Math.ceil(topWallList.length / 5) - 1) * 5;
topWallList.forEach((item, i) => {
  const topWallItem = document.createElement('a');
  topWallItem.setAttribute('class', 'top-wall-item');
  topWallItem.setAttribute('href', item.link || 'http://demo.midwayjs.org/');
  topWallItem.setAttribute('target', '_blank');
  const topWallItemInner = document.createElement('div');
  topWallItemInner.setAttribute('class', 'top-wall-item-inner');
  topWallItemInner.style.backgroundImage = `url('${ item.cover }')`;
  topWallItem.appendChild(topWallItemInner);
  topWallEle.appendChild(topWallItem);
  topWallItemList.push(topWallItem);
  setTimeout(function () {
    topWallItem.style.opacity = 1;
  }, Math.random() * 1000);
});
solutionList.forEach((solutionData) => {
  const solutionItem = document.createElement('a');
  solutionItem.setAttribute('class', 'home-solution button');
  solutionItem.setAttribute('href', solutionData.link || 'http://demo.midwayjs.org/');
  solutionItem.setAttribute('target', '_blank');
  solutionItem.innerHTML = '' + (solutionData.title) + '';
  solutionContainer.appendChild(solutionItem);
});
// render why img
const allImg = Array.from(document.querySelectorAll('.home-why-img'));
if (window.IntersectionObserver) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(function(entry) {
      let box = entry.target;
      if (entry.intersectionRatio >= 0.9) {
        box.classList.add('display');
        box.previousElementSibling.classList.add('display');
      } else if (entry.intersectionRatio < 0.3) {
        box.classList.remove('display');
        box.previousElementSibling.classList.remove('display');
      }
    });
  }, {
    root: null,
    rootMargin: '0px', 
    threshold: [0.0, 0.1, 0.2, 0.3, 0.7, 0.8, 0.9, 1.0]
  });
  allImg.forEach(function (ele) {
    observer.observe(ele);
  });
} else {
  allImg.forEach(function (ele) {
    ele.classList.add('display');
    ele.previousElementSibling.classList.add('display');
  });
}
</script>