Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add inspect page #101

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
6 changes: 1 addition & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ module.exports = {
es6: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 12,
Expand Down
4 changes: 2 additions & 2 deletions packages/playground/ts-example/mock/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ export default (config?: MockConfig) => {
console.log('body>>>>>>>>', body)
console.log('query>>>>>>>>', query)

return {
return Promise.resolve({
code: 0,
message: 'ok',
data: { a: 21, 'import.meta.url': import.meta.url },
}
})
},
},
]
Expand Down
20 changes: 17 additions & 3 deletions packages/vite-plugin-mock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"scripts": {
"clean": "rimraf dist && rimraf es",
"dev": "unbuild --stub",
"build": "unbuild",
"build:inpect": "vite build src/inspect",
"build": "unbuild && npm run build:inpect",
"log": "conventional-changelog -p angular -i CHANGELOG.md -s",
"prepublishOnly": "npm run build"
},
Expand All @@ -48,13 +49,21 @@
},
"homepage": "https://github.com/anncwb/vite-plugin-mock/tree/master/#readme",
"dependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"@vueuse/core": "^10.1.0",
"bundle-require": "^4.0.1",
"chokidar": "^3.5.3",
"connect": "^3.7.0",
"debug": "^4.3.4",
"element-plus": "^2.3.3",
"fast-glob": "^3.2.12",
"ky": "^0.33.3",
"path-to-regexp": "^6.2.1",
"picocolors": "^1.0.0"
"picocolors": "^1.0.0",
"sirv": "^2.0.3",
"unocss": "^0.51.8",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
},
"peerDependencies": {
"mockjs": ">=1.1.0",
Expand All @@ -66,11 +75,16 @@
"@types/connect": "^3.4.35",
"@types/debug": "^4.1.7",
"@types/node": "^16.18.23",
"@vue/compiler-dom": "^3.2.47",
"@vue/compiler-sfc": "^3.2.47",
"mockjs": "^1.1.0",
"rimraf": "^5.0.0",
"tsup": "6.7.0",
"typescript": "^5.0.4",
"unbuild": "^1.2.1",
"vite": "4.2.1"
"unplugin-auto-import": "^0.15.3",
"unplugin-vue-components": "^0.24.1",
"vite": "4.2.1",
"vue-tsc": "^1.6.1"
}
}
17 changes: 13 additions & 4 deletions packages/vite-plugin-mock/src/createMockServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { IncomingMessage, NextHandleFunction } from 'connect'
import { bundleRequire, GetOutputFile, JS_EXT_RE } from 'bundle-require'
import type { ResolvedConfig } from 'vite'

/**
* item format like `${url}+${method}`
*/
export const excludeMock = new Set<string>()

export let mockData: MockMethod[] = []

export async function createMockServer(
Expand Down Expand Up @@ -51,6 +56,10 @@ export async function requestMiddleware(opt: ViteMockOptions) {
const reqUrl = queryParams.pathname

const matchRequest = mockData.find((item) => {
// filter
if (excludeMock.has(`${item.url}+${item.method || 'get'}`)) {
return false
}
if (!reqUrl || !item || !item.url) {
return false
}
Expand Down Expand Up @@ -89,12 +98,12 @@ export async function requestMiddleware(opt: ViteMockOptions) {
const body = await parseJson(req)
res.setHeader('Content-Type', 'application/json')
if (opt) {
res.setHeader('Access-Control-Allow-Credentials', true)
res.setHeader('Access-Control-Allow-Credentials', 'true')
res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '*')
}
res.statusCode = statusCode || 200
const mockResponse = isFunction(response)
? response.bind(self)({ url: req.url as any, body, query, headers: req.headers })
? await response.bind(self)({ url: req.url as any, body, query, headers: req.headers })
: response
res.end(JSON.stringify(Mock.mock(mockResponse)))
}
Expand Down Expand Up @@ -139,7 +148,7 @@ function createWatch(opt: ViteMockOptions, config: ResolvedConfig) {
}

// clear cache
function cleanRequireCache(opt: ViteMockOptions) {
export function cleanRequireCache(opt: ViteMockOptions) {
if (typeof require === 'undefined' || !require.cache) {
return
}
Expand All @@ -151,7 +160,7 @@ function cleanRequireCache(opt: ViteMockOptions) {
})
}

function parseJson(req: IncomingMessage): Promise<Recordable> {
export function parseJson(req: IncomingMessage): Promise<Recordable> {
return new Promise((resolve) => {
let body = ''
let jsonStr = ''
Expand Down
84 changes: 82 additions & 2 deletions packages/vite-plugin-mock/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,25 @@
}
})()

import colors from 'picocolors'
import type { ViteMockOptions } from './types'
import sirv from 'sirv'
import type { Plugin } from 'vite'
import { ResolvedConfig } from 'vite'
import { createMockServer, requestMiddleware } from './createMockServer'
import {
createMockServer,
excludeMock,
mockData,
parseJson,
requestMiddleware,
} from './createMockServer'
import { dirname, resolve } from 'path'
import { fileURLToPath } from 'node:url'

const DIR_CLIENT = resolve(
typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)),
'../dist/inspect',
)

export function viteMockServe(opt: ViteMockOptions = {}): Plugin {
let isDev = false
Expand All @@ -24,13 +39,78 @@ export function viteMockServe(opt: ViteMockOptions = {}): Plugin {
isDev && createMockServer(opt, config)
},

configureServer: async ({ middlewares }) => {
configureServer: async (server) => {
const { middlewares } = server

const { enable = isDev } = opt
if (!enable) {
return
}
const middleware = await requestMiddleware(opt)
middlewares.use(middleware)

/**
* get mock list
*/
middlewares.use('/__mockInspect/list', (req, res, next) => {
res.end(
JSON.stringify(
mockData.map((i) => {
return {
...i,
exclude: excludeMock.has(`${i.url}+${i.method || 'get'}`),
}
}),
),
)
})

/**
* set exclude url
*/
middlewares.use('/__mockInspect/exclude', (req, res, next) => {
const isPost = req.method && req.method.toUpperCase() === 'POST'
if (isPost) {
parseJson(req).then((body: any) => {
if (body && body.urlList) {
excludeMock.clear()
;(body.urlList as string[]).forEach((url) => {
excludeMock.add(url)
})
res.end(JSON.stringify({ code: 0 }))
} else {
next()
}
})
} else {
next()
}
})

/**
* serve inspect page
*/
middlewares.use(
'/__mockInspect',
sirv(DIR_CLIENT, {
single: true,
dev: true,
}),
)

const host =
config.server.host && config.server.host !== '0.0.0.0' ? config.server.host : 'localhost'
const url = `${host}:${config.server.port || 5173}`

const _printUrls = server.printUrls.bind(server)

server.printUrls = () => {
_printUrls()
console.log(
` ${colors.green('➜')} ${colors.bold('Mock Inspect: ')}` +
colors.green(`${config.server.https ? 'https' : 'http'}://${url}/__mockInspect/#/`),
)
}
},
}
}
Expand Down
11 changes: 11 additions & 0 deletions packages/vite-plugin-mock/src/inspect/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">

</script>

<template>
<router-view />
</template>

<style scoped>

</style>
6 changes: 6 additions & 0 deletions packages/vite-plugin-mock/src/inspect/auto-imports.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-auto-import
export {}
declare global {}
25 changes: 25 additions & 0 deletions packages/vite-plugin-mock/src/inspect/components.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'

export {}

declare module '@vue/runtime-core' {
export interface GlobalComponents {
ElButton: typeof import('element-plus/es')['ElButton']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTag: typeof import('element-plus/es')['ElTag']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}
105 changes: 105 additions & 0 deletions packages/vite-plugin-mock/src/inspect/home.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<script setup lang="ts">
import ky from 'ky'
import { computed, ref } from 'vue'
import { MockObj, useMockList } from './hooks/useMockList'

const { mockList, getList } = useMockList()

const filterPath = ref('')
const filterMedth = ref(null as unknown as MockObj['method'])

const filterMockList = computed(()=>{
return mockList.value.filter(i => {
return i.url.includes(filterPath.value)
}).filter(i => {
if(filterMedth.value) return i.method === filterMedth.value
return true
})
})

async function change(mock: MockObj) {
if(mock.include) {
mockList.value.map(i => {
if(i.url === mock.url && i.method === mock.method) {
i.include = false
i.exclude = true
}
})
} else {
mockList.value.map(i => {
if(i.url === mock.url && i.method === mock.method) {
i.include = true
i.exclude = false
}
})
}

await ky.post('./exclude', {
json: {
"urlList": mockList.value.filter(i => i.exclude).map(i => `${i.url}+${i.method || 'get'}`)
}
})
await getList()
}

async function excludeAll() {
await ky.post('./exclude', {
json: {
"urlList": mockList.value.map(i => `${i.url}+${i.method || 'get'}`)
}
})
await getList()
}

async function includeAll() {
await ky.post('./exclude', {
json: {
"urlList": []
}
})
await getList()
}

</script>

<template>
<div class="sticky top-0 z-10 bg-white mb-2">
<el-form :inline="true">
<el-form-item label="Filter">
<span>
<el-input v-model="filterPath" placeholder="Input Path" clearable></el-input>
</span>
<span class="ml-2">
<el-select v-model="filterMedth" placeholder="Select Method" clearable>
<el-option label="get" value="get"></el-option>
<el-option label="post" value="post"></el-option>
<el-option label="put" value="put"></el-option>
<el-option label="delete" value="delete"></el-option>
</el-select>
</span>
</el-form-item>
<el-form-item label="Other">
<el-button @click="excludeAll">Exclude All</el-button>
<el-button @click="includeAll">Include All</el-button>
</el-form-item>
</el-form>

</div>
<el-table :data="filterMockList">
<el-table-column label="Status" width="200">
<template #default="scope">
<el-switch :value="scope.row.include" @click="change(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="Path" prop="url"></el-table-column>
<el-table-column label="Method">
<template #default="scope">
<el-tag>{{ scope.row.method }}</el-tag>
</template>
</el-table-column>
</el-table>
</template>

<style scoped>

</style>
Loading