-
Notifications
You must be signed in to change notification settings - Fork 291
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
luoxue
committed
Dec 17, 2019
1 parent
d6dec9a
commit f0fed9e
Showing
12 changed files
with
655 additions
and
254 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// [mock] | ||
module.exports = ({ | ||
config, | ||
options | ||
}) => { | ||
return () => { | ||
if (!options.mock) return | ||
const createMockMiddleware = require('../lib/createMockMiddleware') | ||
config.devServer.before(app => app.use(createMockMiddleware())) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,5 @@ | |
```bash | ||
webpack-box server:gql | ||
``` | ||
|
||
文档后续在补充,还需要调整,目前可以使用脚手架命令尝试使用 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
## 课时 21:开启 mock | ||
|
||
box.config.js | ||
|
||
```js | ||
{ | ||
mock: true; | ||
} | ||
``` | ||
|
||
```js | ||
└──── mock // mock目录 | ||
│── index.js | ||
└── mock.js | ||
``` | ||
|
||
### 使用 | ||
|
||
mock/index.js | ||
|
||
```js | ||
module.exports = { | ||
// 支持值为 Object 和 Array | ||
"GET /api/users": { users: [1, 2] }, // http://localhost:8888/api/users | ||
// GET POST 可省略 | ||
"/api/users/1": { id: 2 }, // http://localhost:8888/api/users/1 | ||
"/api/users/2": (req, res) => { | ||
// http://localhost:8888/api/users/2 | ||
res.json({ | ||
success: true | ||
}); | ||
}, | ||
"/api/users/3"(req, res) { | ||
// http://127.0.0.1:8888/api/users/3 | ||
res.json({ | ||
success: true | ||
}); | ||
} | ||
}; | ||
``` | ||
|
||
使用 mockjs | ||
|
||
mock/mock.js | ||
|
||
```js | ||
const Mock = require("mockjs"); | ||
|
||
module.exports = { | ||
// 支持值为 Object 和 Array | ||
// http://localhost:8888/api/users/12 | ||
"/api/users/12": Mock.mock({ | ||
// 属性 list 的值是一个数组,其中含有 1 到 10 个元素 | ||
"list|1-30": [ | ||
{ | ||
// 属性 id 是一个自增数,起始值为 1,每次增 1 | ||
"id|+1": 1 | ||
} | ||
] | ||
}) | ||
}; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
const { existsSync } = require('fs') | ||
const { join } = require('path') | ||
const bodyParser = require('body-parser') | ||
const glob = require('glob') | ||
const assert = require('assert') | ||
const chokidar = require('chokidar') | ||
const pathToRegexp = require('path-to-regexp') | ||
|
||
const VALID_METHODS = ['get', 'post', 'put', 'patch', 'delete'] | ||
const BODY_PARSED_METHODS = ['post', 'put', 'patch'] | ||
|
||
module.exports = function getMockMiddleware(/* api */) { | ||
const api = { | ||
debug: require('debug'), | ||
service: { | ||
cwd: process.cwd() | ||
} | ||
} | ||
const { debug } = api | ||
const { cwd } = api.service | ||
const absMockPath = join(cwd, 'mock') | ||
const absConfigPath = join(cwd, 'mock.config.js') | ||
|
||
let mockData = getConfig() | ||
watch() | ||
|
||
function watch() { | ||
if (process.env.WATCH_FILES === 'none') return | ||
const watcher = chokidar.watch([absConfigPath, absMockPath], { | ||
ignoreInitial: true | ||
}) | ||
watcher.on('all', (event, file) => { | ||
debug(`[${event}] ${file}, reload mock data`) | ||
mockData = getConfig() | ||
}) | ||
} | ||
|
||
function getConfig() { | ||
cleanRequireCache() | ||
let ret = null | ||
if (existsSync(absConfigPath)) { | ||
debug(`load mock data from ${absConfigPath}`) | ||
ret = require(absConfigPath) | ||
} else { | ||
const mockFiles = glob.sync('**/*.{js,ts}', { | ||
cwd: absMockPath | ||
}) | ||
debug( | ||
`load mock data from ${absMockPath}, including files ${JSON.stringify( | ||
mockFiles | ||
)}` | ||
) | ||
ret = mockFiles.reduce((memo, mockFile) => { | ||
memo = { | ||
...memo, | ||
...require(join(absMockPath, mockFile)) | ||
} | ||
return memo | ||
}, {}) | ||
} | ||
return normalizeConfig(ret) | ||
} | ||
|
||
function parseKey(key) { | ||
let method = 'get' | ||
let path = key | ||
if (key.indexOf(' ') > -1) { | ||
const splited = key.split(' ') | ||
method = splited[0].toLowerCase() | ||
path = splited[1] | ||
} | ||
assert( | ||
VALID_METHODS.includes(method), | ||
`Invalid method ${method} for path ${path}, please check your mock files.` | ||
) | ||
return { | ||
method, | ||
path | ||
} | ||
} | ||
|
||
function createHandler(method, path, handler) { | ||
return function(req, res, next) { | ||
if (BODY_PARSED_METHODS.includes(method)) { | ||
bodyParser.json({ limit: '5mb', strict: false })(req, res, () => { | ||
bodyParser.urlencoded({ limit: '5mb', extended: true })( | ||
req, | ||
res, | ||
() => { | ||
sendData() | ||
} | ||
) | ||
}) | ||
} else { | ||
sendData() | ||
} | ||
|
||
function sendData() { | ||
if (typeof handler === 'function') { | ||
handler(req, res, next) | ||
} else { | ||
res.json(handler) | ||
} | ||
} | ||
} | ||
} | ||
|
||
function normalizeConfig(config) { | ||
return Object.keys(config).reduce((memo, key) => { | ||
const handler = config[key] | ||
const type = typeof handler | ||
assert( | ||
type === 'function' || type === 'object', | ||
`mock value of ${key} should be function or object, but got ${type}` | ||
) | ||
const { method, path } = parseKey(key) | ||
const keys = [] | ||
const re = pathToRegexp(path, keys) | ||
memo.push({ | ||
method, | ||
path, | ||
re, | ||
keys, | ||
handler: createHandler(method, path, handler) | ||
}) | ||
return memo | ||
}, []) | ||
} | ||
|
||
function cleanRequireCache() { | ||
Object.keys(require.cache).forEach(file => { | ||
if (file === absConfigPath || file.indexOf(absMockPath) > -1) { | ||
delete require.cache[file] | ||
} | ||
}) | ||
} | ||
|
||
function matchMock(req) { | ||
const { path: exceptPath } = req | ||
const exceptMethod = req.method.toLowerCase() | ||
for (const mock of mockData) { | ||
const { method, re, keys } = mock | ||
if (method === exceptMethod) { | ||
const match = re.exec(req.path) | ||
if (match) { | ||
const params = {} | ||
|
||
for (let i = 1; i < match.length; i = i + 1) { | ||
const key = keys[i - 1] | ||
const prop = key.name | ||
const val = decodeParam(match[i]) | ||
|
||
if (val !== undefined || !hasOwnProperty.call(params, prop)) { | ||
params[prop] = val | ||
} | ||
} | ||
req.params = params | ||
return mock | ||
} | ||
} | ||
} | ||
|
||
function decodeParam(val) { | ||
if (typeof val !== 'string' || val.length === 0) { | ||
return val | ||
} | ||
|
||
try { | ||
return decodeURIComponent(val) | ||
} catch (err) { | ||
if (err instanceof URIError) { | ||
err.message = `Failed to decode param ' ${val} '` | ||
err.status = err.statusCode = 400 | ||
} | ||
|
||
throw err | ||
} | ||
} | ||
|
||
return mockData.filter(({ method, re }) => { | ||
return method === exceptMethod && re.test(exceptPath) | ||
})[0] | ||
} | ||
|
||
return (req, res, next) => { | ||
const match = matchMock(req) | ||
if (match) { | ||
debug(`mock matched: [${match.method}] ${match.path}`) | ||
return match.handler(req, res, next) | ||
} else { | ||
return next() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module.exports = { | ||
// 支持值为 Object 和 Array | ||
'GET /api/users': { users: [1, 2] }, // http://localhost:8888/api/users | ||
// GET POST 可省略 | ||
'/api/users/1': { id: 2 }, // http://localhost:8888/api/users/1 | ||
'/api/users/2': (req, res) => { // http://localhost:8888/api/users/2 | ||
res.json({ | ||
success: true | ||
}) | ||
}, | ||
'/api/users/3' (req, res) { // http://127.0.0.1:8888/api/users/3 | ||
res.json({ | ||
success: true | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const Mock = require('mockjs') | ||
|
||
module.exports = { | ||
// 支持值为 Object 和 Array | ||
// http://localhost:8888/api/users/12 | ||
'/api/users/12': Mock.mock({ | ||
// 属性 list 的值是一个数组,其中含有 1 到 10 个元素 | ||
'list|1-30': [{ | ||
// 属性 id 是一个自增数,起始值为 1,每次增 1 | ||
'id|+1': 1 | ||
}] | ||
}) | ||
} |
Oops, something went wrong.