0. 简介

这篇文章主要的目的是分析理解 Express 的源码,网络上 Express 源码分析的文章已经数不胜数,这篇文章准备另辟蹊径,仿制一个 Express 的轮子,通过测试驱动的开发方式不断迭代,正向理解 Express 的代码。

本文是早期创作的另一篇文章的迭代版本,主要是根据文章的历史评论,以及官网的更新进行了细节修正。如果准备通过文章内容了解 Express 的基本原理,前提必须有一些 Express 框架的使用经验,写过一两个基于 Express 框架的应用,否则对于其背后的原理理解起来难以产生共鸣,不易掌握。

文章中的所有源码以及上传到 GitHub,欢迎下载。

1. 神说:“要有光”

我们创建一个新的框架,就叫它 Expross。根据 Duck typing 法则,必须让它看起来像 Express 再说其它。让我们先从 Express 的官网案例入手,确认框架的结构,并尽可能的通过官方案例的测试。

初始框架的结构如下,如果以后不满足需求可以随时更改:

expross
  |
  |-- lib
  |    | 
  |    |-- expross.js
  |
  |-- test
  |    |
  |    |-- index.js
  |
  |-- index.js

上述结构在现在的 npm 包中非常流行,其中 expross/test/index.js 用来保存官方案例,主要用于框架测试。

//官方案例

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

不过在保存之前,需要将前两行替换为我们自己的框架:

const expross = require('../');
const app = expross();

文件 expross/index.js 是 expross 框架的入口。代码主要是用于加载 lib 目录下的 expross.js 文件。

module.exports = require('./lib/expross');

文件 expross/lib/expross.js 用来保存真正的项目核心代码。我们可以通过研究官方示例的前两行代码可以推断出来 Express 变量所代表的是一个函数,进而确定我们的 expross.js 文件只有导出函数才能满足测试文件的要求。所以在文件中添加代码如下:

function createApplication() {
	return {};
}

exports = module.exports = createApplication;

为了迎合测试程序调用的函数需求,暂时将函数实现如下:

function createApplication() {
	return {
		get: function() {
			console.log('expross().get function');
		},

		listen: function() {
			console.log('expross().listen function');
		}
	}
}

目前代码虽然没有实现真正的功能,但至少可以先将测试跑通,函数的核心内容可以在接下来的步骤中不断完善。

运行 node test/index.js 查看结果。