index.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('fs'), require('path'), require('axios'), require('lodash'), require('prettier'), require('@vue/compiler-sfc'), require('magic-string'), require('glob')) :
  3. typeof define === 'function' && define.amd ? define(['exports', 'fs', 'path', 'axios', 'lodash', 'prettier', '@vue/compiler-sfc', 'magic-string', 'glob'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.index = {}, global.fs, global.path, global.axios, global.lodash, global.prettier, global.compilerSfc, global.magicString, global.glob));
  5. })(this, (function (exports, fs, path, axios, lodash, prettier, compilerSfc, magicString, glob) { 'use strict';
  6. const config = {
  7. type: "admin",
  8. reqUrl: "",
  9. demo: false,
  10. eps: {
  11. dist: "./build/cool",
  12. mapping: [
  13. {
  14. // 自定义匹配
  15. custom: ({ propertyName, type }) => {
  16. // 如果没有,返回null或者不返回,则继续遍历其他匹配规则
  17. return null;
  18. },
  19. },
  20. {
  21. type: "string",
  22. test: ["varchar", "text", "simple-json"],
  23. },
  24. {
  25. type: "string[]",
  26. test: ["simple-array"],
  27. },
  28. {
  29. type: "Date",
  30. test: ["datetime", "date"],
  31. },
  32. {
  33. type: "number",
  34. test: ["tinyint", "int", "decimal"],
  35. },
  36. {
  37. type: "BigInt",
  38. test: ["bigint"],
  39. },
  40. ],
  41. },
  42. };
  43. // 根目录
  44. function rootDir(path$1) {
  45. switch (config.type) {
  46. case "app":
  47. return path.join(process.env.UNI_INPUT_DIR, path$1);
  48. default:
  49. return path.join(process.cwd(), path$1);
  50. }
  51. }
  52. // 首字母大写
  53. function firstUpperCase(value) {
  54. return value.replace(/\b(\w)(\w*)/g, function ($0, $1, $2) {
  55. return $1.toUpperCase() + $2;
  56. });
  57. }
  58. // 横杠转驼峰
  59. function toCamel(str) {
  60. return str.replace(/([^-])(?:-+([^-]))/g, function ($0, $1, $2) {
  61. return $1 + $2.toUpperCase();
  62. });
  63. }
  64. // 创建目录
  65. function createDir(path, recursive) {
  66. try {
  67. if (!fs.existsSync(path))
  68. fs.mkdirSync(path, { recursive });
  69. }
  70. catch (err) { }
  71. }
  72. // 读取文件
  73. function readFile(path, json) {
  74. try {
  75. const content = fs.readFileSync(path, "utf8");
  76. return json ? JSON.parse(content) : content;
  77. }
  78. catch (err) { }
  79. return "";
  80. }
  81. // 写入文件
  82. function writeFile(path, data) {
  83. try {
  84. return fs.writeFileSync(path, data);
  85. }
  86. catch (err) { }
  87. return "";
  88. }
  89. // 解析body
  90. function parseJson(req) {
  91. return new Promise((resolve) => {
  92. let d = "";
  93. req.on("data", function (chunk) {
  94. d += chunk;
  95. });
  96. req.on("end", function () {
  97. try {
  98. resolve(JSON.parse(d));
  99. }
  100. catch {
  101. resolve({});
  102. }
  103. });
  104. });
  105. }
  106. function error(message) {
  107. console.log("\x1B[31m%s\x1B[0m", message);
  108. }
  109. let service = {};
  110. let list = [];
  111. let customList = [];
  112. // 获取路径
  113. function getEpsPath(filename) {
  114. return path.join(config.type == "admin" ? config.eps.dist : rootDir(config.eps.dist), filename || "");
  115. }
  116. // 获取方法名
  117. function getNames(v) {
  118. return Object.keys(v).filter((e) => !["namespace", "permission"].includes(e));
  119. }
  120. // 获取数据
  121. async function getData(data) {
  122. // 自定义数据
  123. if (!lodash.isEmpty(data)) {
  124. customList = (data || []).map((e) => {
  125. return {
  126. ...e,
  127. isLocal: true,
  128. };
  129. });
  130. }
  131. // 本地文件
  132. const epsPath = getEpsPath("eps.json");
  133. try {
  134. list = readFile(epsPath, true) || [];
  135. }
  136. catch (err) {
  137. error(`[cool-eps] ${epsPath} 文件异常, ${err.message}`);
  138. }
  139. // 请求地址
  140. let url = config.reqUrl;
  141. switch (config.type) {
  142. case "app":
  143. url += "/app/base/comm/eps";
  144. break;
  145. case "admin":
  146. url += "/admin/base/open/eps";
  147. break;
  148. }
  149. // 请求数据
  150. await axios
  151. .get(url, {
  152. timeout: 5000,
  153. })
  154. .then((res) => {
  155. const { code, data, message } = res.data;
  156. if (code === 1000) {
  157. if (!lodash.isEmpty(data) && data) {
  158. lodash.merge(list, Object.values(data).flat());
  159. }
  160. }
  161. else {
  162. error(`[cool-eps] ${message}`);
  163. }
  164. })
  165. .catch(() => {
  166. error(`[cool-eps] 后端未启动 ➜ ${url}`);
  167. });
  168. // 合并自定义数据
  169. if (lodash.isArray(customList)) {
  170. customList.forEach((e) => {
  171. const d = list.find((a) => e.prefix === a.prefix);
  172. if (d) {
  173. lodash.merge(d, e);
  174. }
  175. else {
  176. list.push(e);
  177. }
  178. });
  179. }
  180. // 设置默认值
  181. list.forEach((e) => {
  182. if (!e.namespace) {
  183. e.namespace = "";
  184. }
  185. if (!e.api) {
  186. e.api = [];
  187. }
  188. });
  189. }
  190. // 创建 json 文件
  191. function createJson() {
  192. const d = list.map((e) => {
  193. return {
  194. prefix: e.prefix,
  195. name: e.name || "",
  196. api: e.api.map((e) => {
  197. return {
  198. name: e.name,
  199. method: e.method,
  200. path: e.path,
  201. };
  202. }),
  203. };
  204. });
  205. fs.createWriteStream(getEpsPath("eps.json"), {
  206. flags: "w",
  207. }).write(JSON.stringify(d));
  208. }
  209. // 创建描述文件
  210. async function createDescribe({ list, service }) {
  211. // 获取类型
  212. function getType({ propertyName, type }) {
  213. for (const map of config.eps.mapping) {
  214. if (map.custom) {
  215. const resType = map.custom({ propertyName, type });
  216. if (resType)
  217. return resType;
  218. }
  219. if (map.test) {
  220. if (map.test.includes(type))
  221. return map.type;
  222. }
  223. }
  224. return type;
  225. }
  226. // 创建 Entity
  227. function createEntity() {
  228. const t0 = [];
  229. for (const item of list) {
  230. if (!item.name)
  231. continue;
  232. const t = [`interface ${item.name} {`];
  233. for (const col of item.columns || []) {
  234. // 描述
  235. t.push("\n");
  236. t.push("/**\n");
  237. t.push(` * ${col.comment}\n`);
  238. t.push(" */\n");
  239. t.push(`${col.propertyName}?: ${getType({
  240. propertyName: col.propertyName,
  241. type: col.type,
  242. })};`);
  243. }
  244. t.push("\n");
  245. t.push("/**\n");
  246. t.push(` * 任意键值\n`);
  247. t.push(" */\n");
  248. t.push(`[key: string]: any;`);
  249. t.push("}");
  250. t0.push(t);
  251. }
  252. return t0.map((e) => e.join("")).join("\n\n");
  253. }
  254. // 创建 Service
  255. function createDts() {
  256. const t0 = [];
  257. const t1 = [
  258. `
  259. type json = any;
  260. type Service = {
  261. request(options?: {
  262. url: string;
  263. method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
  264. data?: any;
  265. params?: any;
  266. headers?: {
  267. [key: string]: any;
  268. },
  269. timeout?: number;
  270. proxy?: boolean;
  271. [key: string]: any;
  272. }): Promise<any>;
  273. `,
  274. ];
  275. // 处理数据
  276. function deep(d, k) {
  277. if (!k)
  278. k = "";
  279. for (const i in d) {
  280. const name = k + toCamel(firstUpperCase(i.replace(/[:]/g, "")));
  281. if (d[i].namespace) {
  282. // 查找配置
  283. const item = list.find((e) => (e.prefix || "") === `/${d[i].namespace}`);
  284. if (item) {
  285. const t = [`interface ${name} {`];
  286. t1.push(`${i}: ${name};`);
  287. // 插入方法
  288. if (item.api) {
  289. // 权限列表
  290. const permission = [];
  291. item.api.forEach((a) => {
  292. // 方法名
  293. const n = toCamel(a.name || lodash.last(a.path.split("/")) || "").replace(/[:\/-]/g, "");
  294. if (n) {
  295. // 参数类型
  296. let q = [];
  297. // 参数列表
  298. const { parameters = [] } = a.dts || {};
  299. parameters.forEach((p) => {
  300. if (p.description) {
  301. q.push(`\n/** ${p.description} */\n`);
  302. }
  303. if (p.name.includes(":")) {
  304. return false;
  305. }
  306. const a = `${p.name}${p.required ? "" : "?"}`;
  307. const b = `${p.schema.type || "string"}`;
  308. q.push(`${a}: ${b},`);
  309. });
  310. if (lodash.isEmpty(q)) {
  311. q = ["any"];
  312. }
  313. else {
  314. q.unshift("{");
  315. q.push("}");
  316. }
  317. // 返回类型
  318. let res = "";
  319. // 实体名
  320. const en = item.name || "any";
  321. switch (a.path) {
  322. case "/page":
  323. res = `
  324. {
  325. pagination: { size: number; page: number; total: number; [key: string]: any };
  326. list: ${en} [];
  327. [key: string]: any;
  328. }
  329. `;
  330. break;
  331. case "/list":
  332. res = `${en} []`;
  333. break;
  334. case "/info":
  335. res = en;
  336. break;
  337. default:
  338. res = "any";
  339. break;
  340. }
  341. // 描述
  342. t.push("\n");
  343. t.push("/**\n");
  344. t.push(` * ${a.summary || n}\n`);
  345. t.push(" */\n");
  346. t.push(`${n}(data${q.length == 1 ? "?" : ""}: ${q.join("")}): Promise<${res}>;`);
  347. permission.push(n);
  348. }
  349. });
  350. // 权限标识
  351. t.push("\n");
  352. t.push("/**\n");
  353. t.push(" * 权限标识\n");
  354. t.push(" */\n");
  355. t.push(`permission: { ${permission
  356. .map((e) => `${e}: string;`)
  357. .join("\n")} };`);
  358. // 权限状态
  359. t.push("\n");
  360. t.push("/**\n");
  361. t.push(" * 权限状态\n");
  362. t.push(" */\n");
  363. t.push(`_permission: { ${permission
  364. .map((e) => `${e}: boolean;`)
  365. .join("\n")} };`);
  366. // 请求
  367. t.push("\n");
  368. t.push("/**\n");
  369. t.push(" * 请求\n");
  370. t.push(" */\n");
  371. t.push(`request: Service['request']`);
  372. }
  373. t.push("}");
  374. t0.push(t);
  375. }
  376. }
  377. else {
  378. t1.push(`${i}: {`);
  379. deep(d[i], name);
  380. t1.push(`},`);
  381. }
  382. }
  383. }
  384. // 深度
  385. deep(service);
  386. // 结束
  387. t1.push("}");
  388. // 追加
  389. t0.push(t1);
  390. return t0.map((e) => e.join("")).join("\n\n");
  391. }
  392. // 文件内容
  393. const text = `
  394. declare namespace Eps {
  395. ${createEntity()}
  396. ${createDts()}
  397. }
  398. `;
  399. // 文本内容
  400. const content = await prettier.format(text, {
  401. parser: "typescript",
  402. useTabs: true,
  403. tabWidth: 4,
  404. endOfLine: "lf",
  405. semi: true,
  406. singleQuote: false,
  407. printWidth: 100,
  408. trailingComma: "none",
  409. });
  410. // 创建 eps 描述文件
  411. fs.createWriteStream(getEpsPath("eps.d.ts"), {
  412. flags: "w",
  413. }).write(content);
  414. }
  415. // 创建 service
  416. function createService() {
  417. list.forEach((e) => {
  418. // 分隔路径
  419. const arr = e.prefix
  420. .replace(/\//, "")
  421. .replace(config.type, "")
  422. .split("/")
  423. .filter(Boolean)
  424. .map(toCamel);
  425. // 遍历
  426. function deep(d, i) {
  427. const k = arr[i];
  428. if (k) {
  429. // 是否最后一个
  430. if (arr[i + 1]) {
  431. if (!d[k]) {
  432. d[k] = {};
  433. }
  434. deep(d[k], i + 1);
  435. }
  436. else {
  437. // 不存在则创建
  438. if (!d[k]) {
  439. d[k] = {
  440. namespace: e.prefix.substring(1, e.prefix.length),
  441. permission: {},
  442. };
  443. }
  444. // 创建方法
  445. e.api.forEach((a) => {
  446. // 方法名
  447. const n = a.path.replace("/", "");
  448. if (n && !/[-:]/g.test(n)) {
  449. d[k][n] = a;
  450. }
  451. });
  452. // 创建权限
  453. getNames(d[k]).forEach((e) => {
  454. d[k].permission[e] =
  455. `${d[k].namespace.replace(`${config.type}/`, "")}/${e}`.replace(/\//g, ":");
  456. });
  457. }
  458. }
  459. }
  460. deep(service, 0);
  461. });
  462. }
  463. // 创建 eps
  464. async function createEps(query) {
  465. // 获取数据
  466. await getData(query?.list || []);
  467. // 创建 service
  468. createService();
  469. // 创建目录
  470. createDir(getEpsPath(), true);
  471. // 创建 json 文件
  472. createJson();
  473. // 创建描述文件
  474. createDescribe({ service, list });
  475. return {
  476. service,
  477. list,
  478. };
  479. }
  480. function createTag(code, id) {
  481. if (/\.vue$/.test(id)) {
  482. let s;
  483. const str = () => s || (s = new magicString(code));
  484. const { descriptor } = compilerSfc.parse(code);
  485. if (!descriptor.script && descriptor.scriptSetup) {
  486. const res = compilerSfc.compileScript(descriptor, { id });
  487. const { name, lang } = res.attrs;
  488. str().appendLeft(0, `<script lang="${lang}">
  489. import { defineComponent } from 'vue'
  490. export default defineComponent({
  491. name: "${name}"
  492. })
  493. <\/script>`);
  494. return {
  495. map: str().generateMap(),
  496. code: str().toString()
  497. };
  498. }
  499. }
  500. return null;
  501. }
  502. function findFiles(dir) {
  503. const res = [];
  504. const dirs = fs.readdirSync(dir, {
  505. withFileTypes: true,
  506. });
  507. for (const d of dirs) {
  508. if (d.isDirectory()) {
  509. res.push(...findFiles(dir + d.name + "/"));
  510. }
  511. else {
  512. if (path.extname(d.name) == ".svg") {
  513. const svg = fs.readFileSync(dir + d.name)
  514. .toString()
  515. .replace(/(\r)|(\n)/g, "")
  516. .replace(/<svg([^>+].*?)>/, (_, $2) => {
  517. let width = 0;
  518. let height = 0;
  519. let content = $2.replace(/(width|height)="([^>+].*?)"/g, (_, s2, s3) => {
  520. if (s2 === "width") {
  521. width = s3;
  522. }
  523. else if (s2 === "height") {
  524. height = s3;
  525. }
  526. return "";
  527. });
  528. if (!/(viewBox="[^>+].*?")/g.test($2)) {
  529. content += `viewBox="0 0 ${width} ${height}"`;
  530. }
  531. return `<symbol id="icon-${d.name.replace(".svg", "")}" ${content}>`;
  532. })
  533. .replace("</svg>", "</symbol>");
  534. res.push(svg);
  535. }
  536. }
  537. }
  538. return res;
  539. }
  540. function createSvg(html) {
  541. const res = findFiles(rootDir("./src/"));
  542. return html.replace("<body>", `<body>
  543. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
  544. ${res.join("")}
  545. </svg>`);
  546. }
  547. // 创建文件
  548. async function createMenu(options) {
  549. // 格式化内容
  550. const content = await prettier.format(options.code, {
  551. parser: "vue",
  552. useTabs: true,
  553. tabWidth: 4,
  554. endOfLine: "lf",
  555. semi: true,
  556. jsxBracketSameLine: true,
  557. singleQuote: false,
  558. printWidth: 100,
  559. trailingComma: "none",
  560. });
  561. // 目录路径
  562. const dir = (options.viewPath || "").split("/");
  563. // 文件名
  564. const fname = dir.pop();
  565. // 源码路径
  566. const srcPath = `./src/${dir.join("/")}`;
  567. // 创建目录
  568. createDir(srcPath, true);
  569. // 创建文件
  570. fs.createWriteStream(path.join(srcPath, fname || "demo"), {
  571. flags: "w",
  572. }).write(content);
  573. }
  574. function base() {
  575. return {
  576. name: "vite-cool-base",
  577. enforce: "pre",
  578. configureServer(server) {
  579. server.middlewares.use(async (req, res, next) => {
  580. function done(data) {
  581. res.writeHead(200, { "Content-Type": "text/html;charset=UTF-8" });
  582. res.end(JSON.stringify(data));
  583. }
  584. if (req.originalUrl?.includes("__cool")) {
  585. const body = await parseJson(req);
  586. switch (req.url) {
  587. // 快速创建菜单
  588. case "/__cool_createMenu":
  589. await createMenu(body);
  590. break;
  591. // 创建描述文件
  592. case "/__cool_eps":
  593. await createEps(body);
  594. break;
  595. default:
  596. return done({
  597. code: 1001,
  598. message: "未知请求",
  599. });
  600. }
  601. done({
  602. code: 1000,
  603. });
  604. }
  605. else {
  606. next();
  607. }
  608. });
  609. },
  610. transform(code, id) {
  611. if (config.type == "admin") {
  612. return createTag(code, id);
  613. }
  614. return code;
  615. },
  616. transformIndexHtml(html) {
  617. if (config.type == "admin") {
  618. return createSvg(html);
  619. }
  620. return html;
  621. },
  622. };
  623. }
  624. function demo(enable) {
  625. const virtualModuleIds = ["virtual:demo"];
  626. return {
  627. name: "vite-cool-demo",
  628. enforce: "pre",
  629. resolveId(id) {
  630. if (virtualModuleIds.includes(id)) {
  631. return "\0" + id;
  632. }
  633. },
  634. async load(id) {
  635. if (id === "\0virtual:demo") {
  636. const demo = {};
  637. if (enable) {
  638. const files = await glob.glob(rootDir("./src/modules/demo/views/crud/components") + "/**", {
  639. stat: true,
  640. withFileTypes: true,
  641. });
  642. for (const file of files) {
  643. if (file.isFile()) {
  644. const p = path.join(file.path, file.name);
  645. demo[p
  646. .replace(/\\/g, "/")
  647. .split("src/modules/demo/views/crud/components/")[1]] = fs.readFileSync(p, "utf-8");
  648. }
  649. }
  650. }
  651. return `
  652. export const demo = ${JSON.stringify(demo)};
  653. `;
  654. }
  655. },
  656. };
  657. }
  658. async function createCtx() {
  659. let ctx = {};
  660. if (config.type == "app") {
  661. const manifest = readFile(rootDir("manifest.json"), true);
  662. // 文件路径
  663. const ctxPath = rootDir("pages.json");
  664. // 页面配置
  665. ctx = readFile(ctxPath, true);
  666. // 原数据,做更新比较用
  667. const ctxData = lodash.cloneDeep(ctx);
  668. // 删除临时页面
  669. ctx.pages = ctx.pages?.filter((e) => !e.isTemp);
  670. ctx.subPackages = ctx.subPackages?.filter((e) => !e.isTemp);
  671. // 加载 uni_modules 配置文件
  672. const files = await glob.glob(rootDir("uni_modules") + "/**/pages_init.json", {
  673. stat: true,
  674. withFileTypes: true,
  675. });
  676. for (const file of files) {
  677. if (file.isFile()) {
  678. const { pages = [], subPackages = [] } = readFile(path.join(file.path, file.name), true);
  679. // 合并到 pages 中
  680. [...pages, ...subPackages].forEach((e) => {
  681. e.isTemp = true;
  682. const isSub = !!e.root;
  683. const d = isSub
  684. ? ctx.subPackages?.find((a) => a.root == e.root)
  685. : ctx.pages?.find((a) => a.path == e.path);
  686. if (d) {
  687. lodash.assign(d, e);
  688. }
  689. else {
  690. if (isSub) {
  691. ctx.subPackages?.unshift(e);
  692. }
  693. else {
  694. ctx.pages?.unshift(e);
  695. }
  696. }
  697. });
  698. }
  699. }
  700. // 是否需要更新 pages.json
  701. if (!lodash.isEqual(ctxData, ctx)) {
  702. console.log("[cool-ctx] pages updated");
  703. writeFile(ctxPath, JSON.stringify(ctx, null, 4));
  704. }
  705. // appid
  706. ctx.appid = manifest.appid;
  707. }
  708. if (config.type == "admin") {
  709. const list = fs.readdirSync(rootDir("./src/modules"));
  710. ctx.modules = list.filter((e) => !e.includes("."));
  711. }
  712. return ctx;
  713. }
  714. async function virtual() {
  715. const virtualModuleIds = ["virtual:eps", "virtual:ctx"];
  716. const eps = await createEps();
  717. const ctx = await createCtx();
  718. return {
  719. name: "vite-cool-virtual",
  720. enforce: "pre",
  721. handleHotUpdate({ file, server }) {
  722. if (!["pages.json", "dist", "build/cool"].some((e) => file.includes(e))) {
  723. createCtx();
  724. createEps().then((data) => {
  725. // 通知客户端刷新
  726. server.ws.send({
  727. type: "custom",
  728. event: "eps-update",
  729. data,
  730. });
  731. });
  732. }
  733. },
  734. resolveId(id) {
  735. if (virtualModuleIds.includes(id)) {
  736. return "\0" + id;
  737. }
  738. },
  739. load(id) {
  740. if (id === "\0virtual:eps") {
  741. return `
  742. export const eps = ${JSON.stringify(eps)}
  743. `;
  744. }
  745. if (id === "\0virtual:ctx") {
  746. return `
  747. export const ctx = ${JSON.stringify(ctx)}
  748. `;
  749. }
  750. },
  751. };
  752. }
  753. function cool(options) {
  754. // 应用类型,admin | app
  755. config.type = options.type;
  756. // 请求地址
  757. config.reqUrl = options.proxy["/dev/"].target;
  758. // Eps
  759. if (options.eps) {
  760. const { dist, mapping } = options.eps;
  761. if (dist) {
  762. config.eps.dist = dist;
  763. }
  764. if (mapping) {
  765. config.eps.mapping.unshift(...mapping);
  766. }
  767. }
  768. return [base(), virtual(), demo(options.demo)];
  769. }
  770. exports.cool = cool;
  771. }));