forked from natuka/web.puabadge.com
Initial commit
This commit is contained in:
commit
84061c9a18
243 files changed
+63148
No files matched your search
@@ -0,0 +1,127 @@
|
||||
const { join } = require('path')
|
||||
const url = require('url')
|
||||
const chokidar = require('chokidar')
|
||||
const signale = require('signale')
|
||||
const { match } = require('path-to-regexp')
|
||||
const { initMock, getMatchMock } = require('./getMockData')
|
||||
const { winPath } = require('./utils')
|
||||
const { configBabelRegister } = require('./registerBabel')
|
||||
let watcher
|
||||
function getPaths(cwd) {
|
||||
const winCwd = winPath(cwd)
|
||||
const absMockPath = winPath(join(winCwd, 'mock'))
|
||||
return {
|
||||
absMockPath,
|
||||
}
|
||||
}
|
||||
|
||||
function parseJson(req) {
|
||||
return new Promise((resolve) => {
|
||||
let body = ''
|
||||
let jsonStr = ''
|
||||
req.on('data', (chunk) => {
|
||||
body += chunk
|
||||
})
|
||||
req.on('end', () => {
|
||||
try {
|
||||
jsonStr = JSON.parse(body)
|
||||
}
|
||||
catch (err) {
|
||||
jsonStr = ''
|
||||
}
|
||||
resolve(jsonStr)
|
||||
})
|
||||
})
|
||||
}
|
||||
const defaultOptions = {
|
||||
watch: true,
|
||||
cwd: process.cwd(), // 配置需要mock的url
|
||||
mockUrlList: [],
|
||||
// 是否开启mock
|
||||
enable: true,
|
||||
}
|
||||
function initWatchMockFiles(paths) {
|
||||
// chokidar 在 windows 下使用反斜杠组成的 glob 无法正确 watch 文件变动
|
||||
// ref: https://github.com/paulmillr/chokidar/issues/777
|
||||
const absPagesGlobPath = winPath(join('./mock', '**/*.[jt]s'))
|
||||
watcher = chokidar.watch([...['./mock'], absPagesGlobPath], {
|
||||
ignoreInitial: true,
|
||||
})
|
||||
watcher.on('all', (event, file) => {
|
||||
signale.info(`[${event}] ${file}, reload mock data`)
|
||||
cleanRequireCache(paths)
|
||||
})
|
||||
process.once('SIGINT', () => {
|
||||
watcher.close()
|
||||
})
|
||||
}
|
||||
function cleanRequireCache(paths) {
|
||||
Object.keys(require.cache).forEach((file) => {
|
||||
if (
|
||||
paths.some((path) => {
|
||||
return winPath(file).includes(path)
|
||||
})
|
||||
)
|
||||
delete require.cache[file]
|
||||
})
|
||||
}
|
||||
module.exports = function (opts) {
|
||||
const options = Object.assign({}, defaultOptions, opts)
|
||||
const { absMockPath } = getPaths(options.cwd)
|
||||
const paths = [absMockPath]
|
||||
if (options.enable) {
|
||||
// vite热更新时关闭上一个进程
|
||||
if (watcher)
|
||||
watcher.close()
|
||||
|
||||
configBabelRegister(paths, {
|
||||
cwd: options.cwd,
|
||||
})
|
||||
initMock(options)
|
||||
if (options.watch)
|
||||
initWatchMockFiles(paths)
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'vite:mock',
|
||||
enforce: 'pre',
|
||||
configureServer({ middlewares }) {
|
||||
if (!options.enable)
|
||||
return
|
||||
|
||||
const middleware = async (req, res, next) => {
|
||||
const matchMock = getMatchMock(req.url)
|
||||
if (matchMock) {
|
||||
let queryParams = {}
|
||||
|
||||
if (req.url)
|
||||
// eslint-disable-next-line n/no-deprecated-api
|
||||
queryParams = url.parse(req.url, true)
|
||||
|
||||
const reqUrl = queryParams.pathname
|
||||
let query = queryParams.query
|
||||
if (reqUrl) {
|
||||
const isGet = req.method && req.method.toUpperCase() === 'GET'
|
||||
if ((isGet && JSON.stringify(query) === '{}') || !isGet) {
|
||||
const urlMatch = match(url, { decode: decodeURIComponent })
|
||||
const params = urlMatch(reqUrl).params
|
||||
if (JSON.stringify(params) !== '{}')
|
||||
query = urlMatch(reqUrl).params || {}
|
||||
|
||||
else
|
||||
query = queryParams.query || {}
|
||||
}
|
||||
}
|
||||
const body = await parseJson(req)
|
||||
res.setHeader('Content-Type', 'application/json;charset=utf-8')
|
||||
res.send = opt => res.end(JSON.stringify(opt))
|
||||
res.json = opt => res.end(JSON.stringify(opt))
|
||||
matchMock.handler({ url: req.url, body, query, headers: req.headers }, res)
|
||||
return
|
||||
}
|
||||
next()
|
||||
}
|
||||
middlewares.use(middleware)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
const { pathToRegexp } = require('path-to-regexp')
|
||||
const signale = require('signale')
|
||||
const { winPath } = require('./utils')
|
||||
let _mockconfig = {}
|
||||
const cwd = process.cwd()
|
||||
let mockList = []
|
||||
// 获取mock文件列表
|
||||
function getMockFile() {
|
||||
let mockFiles = glob
|
||||
.sync('mock/**/*.[jt]s', {
|
||||
cwd,
|
||||
ignore: [],
|
||||
})
|
||||
.map(p => path.join(cwd, p))
|
||||
// windows下路径处理
|
||||
mockFiles = mockFiles.map(p => winPath(p))
|
||||
|
||||
return mockFiles
|
||||
}
|
||||
|
||||
// 获取mock文件数据
|
||||
function getMockData(files) {
|
||||
let mockData = {}
|
||||
files.forEach((mockFile) => {
|
||||
try {
|
||||
const m = require(mockFile)
|
||||
mockData = Object.assign(mockData, m.default || m)
|
||||
return mockData
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
throw e
|
||||
}
|
||||
})
|
||||
return mockData
|
||||
}
|
||||
|
||||
// mock数据格式化
|
||||
function parseMockData(config) {
|
||||
mockList = Object.keys(config).reduce((list, key) => {
|
||||
const handler = config[key]
|
||||
const { method, path } = parseMockUrl(key)
|
||||
const keys = []
|
||||
const re = pathToRegexp(path, keys)
|
||||
list.push({
|
||||
method,
|
||||
path,
|
||||
re,
|
||||
keys,
|
||||
handler: mockHandle(handler),
|
||||
})
|
||||
return list
|
||||
}, [])
|
||||
}
|
||||
function getMatchMock(url) {
|
||||
return (
|
||||
_mockconfig.mockUrlList.findIndex((whiteUrl) => {
|
||||
if (Object.prototype.toString.call(whiteUrl) === '[object RegExp]')
|
||||
return whiteUrl.test(url)
|
||||
|
||||
else
|
||||
return url.includes(whiteUrl)
|
||||
}) !== -1 && mockList.filter(item => url.includes(item.path)).sort((a, b) => b.path.length - a.path.length)[0]
|
||||
)
|
||||
}
|
||||
function mockHandle(handler) {
|
||||
if (Object.prototype.toString.call(handler) === '[object Function]')
|
||||
return handler
|
||||
|
||||
return (_, res) => {
|
||||
return res.end(JSON.stringify(handler))
|
||||
}
|
||||
}
|
||||
|
||||
function parseMockUrl(key) {
|
||||
let method = 'get'
|
||||
let path = key
|
||||
if (/\s+/.test(key)) {
|
||||
const splited = key.split(/\s+/)
|
||||
method = splited[0].toLowerCase()
|
||||
path = splited[1]
|
||||
}
|
||||
return {
|
||||
method,
|
||||
path,
|
||||
}
|
||||
}
|
||||
|
||||
function initMock(config) {
|
||||
try {
|
||||
_mockconfig = config
|
||||
mockList = []
|
||||
const files = getMockFile()
|
||||
const mockData = getMockData(files)
|
||||
parseMockData(mockData)
|
||||
}
|
||||
catch (e) {
|
||||
signale.warn('init mock failed')
|
||||
signale.fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getMatchMock,
|
||||
initMock,
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
const { join, isAbsolute } = require('path')
|
||||
const { existsSync } = require('fs')
|
||||
const { winPath } = require('./utils')
|
||||
let files = null
|
||||
|
||||
function initFiles(cwd) {
|
||||
if (files)
|
||||
return
|
||||
files = getConfigPaths(cwd)
|
||||
}
|
||||
function getConfigPaths(cwd) {
|
||||
const env = process.env.UMI_ENV
|
||||
return [
|
||||
join(cwd, 'config/'),
|
||||
join(cwd, '.umirc.js'),
|
||||
join(cwd, '.umirc.ts'),
|
||||
join(cwd, '.umirc.local.js'),
|
||||
join(cwd, '.umirc.local.ts'),
|
||||
...(env ? [join(cwd, `.umirc.${env}.js`), join(cwd, `.umirc.${env}.ts`)] : []),
|
||||
]
|
||||
}
|
||||
|
||||
function addBabelRegisterFiles(extraFiles, { cwd }) {
|
||||
initFiles(cwd)
|
||||
files = files.concat(...extraFiles)
|
||||
}
|
||||
function addBabelRegister({ cwd }) {
|
||||
initFiles(cwd)
|
||||
const only = files.map((f) => {
|
||||
const fullPath = isAbsolute(f) ? f : join(cwd, f)
|
||||
return winPath(fullPath)
|
||||
})
|
||||
|
||||
let absSrcPath = join(cwd, 'src')
|
||||
if (!existsSync(absSrcPath))
|
||||
absSrcPath = cwd
|
||||
|
||||
registerBabel({
|
||||
// only suport glob
|
||||
// ref: https://babeljs.io/docs/en/next/babel-core.html#configitem-type
|
||||
only,
|
||||
babelPreset: [
|
||||
require.resolve('@babel/preset-env'),
|
||||
{
|
||||
targets: { browsers: ['last 2 versions'] },
|
||||
loose: false,
|
||||
modules: 'commonjs',
|
||||
exclude: [
|
||||
'transform-typeof-symbol',
|
||||
'transform-unicode-regex',
|
||||
'transform-sticky-regex',
|
||||
'transform-new-target',
|
||||
'transform-modules-umd',
|
||||
'transform-modules-systemjs',
|
||||
'transform-modules-amd',
|
||||
'transform-literals',
|
||||
],
|
||||
},
|
||||
],
|
||||
babelPlugins: [
|
||||
[
|
||||
require.resolve('babel-plugin-module-resolver'),
|
||||
{
|
||||
alias: {
|
||||
'@': absSrcPath,
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
})
|
||||
}
|
||||
function configBabelRegister(files, { cwd }) {
|
||||
addBabelRegisterFiles(files, {
|
||||
cwd,
|
||||
})
|
||||
addBabelRegister({
|
||||
cwd,
|
||||
})
|
||||
}
|
||||
function registerBabel(opts = {}) {
|
||||
const { only, ignore, babelPreset, babelPlugins } = opts
|
||||
if (!process.env.IS_FROM_UMI_TEST) {
|
||||
require('@babel/register')({
|
||||
presets: [require.resolve('@babel/preset-typescript'), babelPreset],
|
||||
plugins: babelPlugins || [],
|
||||
only,
|
||||
ignore,
|
||||
extensions: ['.es6', '.es', '.jsx', '.js', '.mjs', '.ts', '.tsx'],
|
||||
babelrc: false,
|
||||
cache: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { addBabelRegisterFiles, addBabelRegister, configBabelRegister }
|
||||
@@ -0,0 +1,9 @@
|
||||
const slash = require('slash2')
|
||||
|
||||
const winPath = function (path) {
|
||||
return slash(path)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
winPath,
|
||||
}
|
||||
Reference in new issue
Block a user