From e8eb9a42f0f0c012f66d93f2c114189540e6e7d2 Mon Sep 17 00:00:00 2001 From: leihaohao Date: Mon, 9 Aug 2021 11:35:23 +0800 Subject: [PATCH 1/4] =?UTF-8?q?build:=20=E5=88=9B=E5=BB=BA=20devui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加创建 devui.ts 脚本 - package.json 增加 build:devui 命令 --- package.json | 4 + scripts/create-devui.js | 187 ++++++++++++++++++++++++++++++++++++++++ yarn.lock | 11 ++- 3 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 scripts/create-devui.js diff --git a/package.json b/package.json index bbac5659..2c4d0ec7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dev": "vite", "build": "vite build", "build:lib": "vite build --config vite.config.build.ts && cp package.json dist && cp README.md dist", + "build:devui": "node scripts/create-devui", "test": "jest --config jest.config.js", "ls-lint": "ls-lint", "lint": "eslint \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", @@ -46,6 +47,7 @@ "@commitlint/cli": "^11.0.0", "@commitlint/config-conventional": "^11.0.0", "@ls-lint/ls-lint": "^1.10.0", + "@types/fs-extra": "^9.0.12", "@types/jest": "^26.0.23", "@typescript-eslint/eslint-plugin": "^4.27.0", "@typescript-eslint/parser": "^4.27.0", @@ -61,9 +63,11 @@ "esbuild-register": "^2.6.0", "eslint": "^7.28.0", "eslint-plugin-vue": "^7.11.1", + "fs-extra": "^10.0.0", "husky": "^4.3.7", "jest": "^27.0.4", "lint-staged": "^11.0.0", + "lodash": "^4.17.21", "sass": "^1.32.2", "shelljs": "^0.8.4", "stylelint": "^13.13.1", diff --git a/scripts/create-devui.js b/scripts/create-devui.js new file mode 100644 index 00000000..0d7c53ff --- /dev/null +++ b/scripts/create-devui.js @@ -0,0 +1,187 @@ +const fs = require('fs-extra') +const _ = require('lodash') +const { resolve, relative } = require('path') + +const DEVUI_DIR = resolve(__dirname, '../devui') +const DEVUI_DIRECTIVE_DIR = resolve(DEVUI_DIR, 'directives') +const DEVUI_FILE = resolve(DEVUI_DIR, 'vue-devui.ts') +const DEVUI_PREFIX = 'D' +const DEVUI_IGNORE_DIRS = ['shared', 'style', 'directives'] +const DEVUI_DIRECTIVE_IGNORE_DIRS = [] +const INDEX_FILE = 'index.ts' + +function bigCamelCase(str) { + return _.upperFirst(_.camelCase(str)) +} + +function getUseName(p) { + return p.startsWith('use') ? p.slice(3) : p +} + +function resolveDirFileInfo(targetDir, ignoreDirs = []) { + return fs + .readdirSync(targetDir) + .filter( + (dir) => + // 过滤:必须是目录,且不存在与忽略目录内,拥有 INDEX_FILE + fs.statSync(resolve(targetDir, dir)).isDirectory() && + !ignoreDirs.includes(dir) && + fs.existsSync(resolve(targetDir, dir, INDEX_FILE)) + ) + .map((dir) => ({ + name: DEVUI_PREFIX + bigCamelCase(dir), + dirname: dir, + path: resolve(targetDir, dir, INDEX_FILE) + })) +} + +function parseExportByFileInfo(fileInfo) { + const exportModule = {} + const componentIndexContent = fs.readFileSync(fileInfo.path, { encoding: 'utf-8' }) + + const exportRe = /export/ + const defaultRe = /export (\{[\s\n])?(\s*)default/ + const useRe = /export {([\s\n])?(\s*)use[A-Z]/ + + if (!exportRe.test(componentIndexContent)) { + return exportModule + } + + if (defaultRe.test(componentIndexContent)) { + exportModule.default = fileInfo.name + } + + if (useRe.test(componentIndexContent)) { + const useArr = [] + + let searchContent = componentIndexContent + while (searchContent.search(useRe) !== -1) { + const reStartIndex = componentIndexContent.search(useRe) + const useStartIndex = componentIndexContent.indexOf('use', reStartIndex) + const useEndIndex = componentIndexContent.indexOf('}', useStartIndex) + + const useContent = componentIndexContent.slice(useStartIndex, useEndIndex) + + useContent + .replace(/(\s|\r|\n)/g, '') + .split(',') + .forEach((use) => useArr.push(use)) + + searchContent = componentIndexContent.slice(useEndIndex) + } + + exportModule.use = useArr + } + + if (!_.isEmpty(exportModule)) { + exportModule.fileInfo = fileInfo + } + + return exportModule +} + +function createTemplate(exportModules = []) { + const packages = [] + + const importPackageStr = exportModules + .map((module) => { + const hasDefault = 'default' in module + const hasUse = 'use' in module + + const component = hasDefault ? module.default : '' + const use = hasUse ? module.use.join(', ') : '' + const relativePath = relative(DEVUI_FILE, module.fileInfo.path) + .replace(/\\/g, '/') + .replace('..', '.') + .replace('/' + INDEX_FILE, '') + + const importStr = `import ${component}${ + hasUse ? `${hasDefault ? ', {' : '{'} ${use} }` : '' + } from '${relativePath}'` + + if (hasDefault) { + packages.push(module.default) + } + + if (hasUse) { + packages.push(...module.use) + } + + return importStr + }) + .join('\n') + + const template = ` +import { App } from 'vue' + +${importPackageStr} + +${packages + .filter((p) => p.startsWith('use')) + .map((p) => `const ${getUseName(p)} = registerInstall(${p})`) + .join('\n')} + +const packages = [ + ${packages.map((p) => getUseName(p)).join(',\n ')} +].map(registerInstall) + +function registerInstall(pkg: any) { + if ('install' in pkg) return pkg + + pkg.install = function(app: App) { + if (pkg.installed) return + + if ('setup' in pkg) { + app.component(pkg.name, pkg) + } else if ([${packages.filter((p) => !/^(D|use)/.test(p)).join(', ')}].includes(pkg.name)) { + app.directive(pkg.name, pkg) + } else { + app.config.globalProperties[\`\$\${pkg.name.replace(/^use/, (c: any) => c.slice(-1).toLowerCase())}\`] = pkg + } + } + + return pkg +} + +export { + ${packages.map((p) => (p.startsWith('use') ? `${p},\n ${getUseName(p)}` : p)).join(',\n ')} +} + +export default { + version: '0.0.1', + install(app: App) { + packages.forEach((p) => app.use(p)) + } +} +` + + return template +} + +function createDevui() { + const componentFileInfo = resolveDirFileInfo(DEVUI_DIR, DEVUI_IGNORE_DIRS) + const directiveFileInfo = resolveDirFileInfo(DEVUI_DIRECTIVE_DIR, DEVUI_DIRECTIVE_IGNORE_DIRS) + const exportModules = [] + + componentFileInfo.forEach((f) => { + const em = parseExportByFileInfo(f) + + if (_.isEmpty(em)) return + + exportModules.push(em) + }) + + directiveFileInfo.forEach((f) => { + const em = parseExportByFileInfo(f) + + if (_.isEmpty(em)) return + + exportModules.push(_.update(em, 'default', (n) => n.slice(1))) + }) + + const template = createTemplate(exportModules) + + fs.writeFile(DEVUI_FILE, template, { encoding: 'utf-8' }) +} + +createDevui() diff --git a/yarn.lock b/yarn.lock index 42c5f811..b6991355 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1666,6 +1666,13 @@ resolved "https://registry.nlark.com/@types/estree/download/@types/estree-0.0.48.tgz#18dc8091b285df90db2f25aa7d906cfc394b7f74" integrity sha1-GNyAkbKF35DbLyWqfZBs/DlLf3Q= +"@types/fs-extra@^9.0.12": + version "9.0.12" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.12.tgz#9b8f27973df8a7a3920e8461517ebf8a7d4fdfaf" + integrity sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw== + dependencies: + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.nlark.com/@types/graceful-fs/download/@types/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -3627,8 +3634,8 @@ form-data@^3.0.0: fs-extra@^10.0.0: version "10.0.0" - resolved "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" - integrity sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E= + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" -- Gitee From 85eb8a2144e39b66ad851416bc9d386161b5d40d Mon Sep 17 00:00:00 2001 From: leihaohao Date: Mon, 9 Aug 2021 11:48:11 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/create-devui.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/create-devui.js b/scripts/create-devui.js index 0d7c53ff..b38fe3b0 100644 --- a/scripts/create-devui.js +++ b/scripts/create-devui.js @@ -111,6 +111,8 @@ function createTemplate(exportModules = []) { }) .join('\n') + const directives = packages.filter((p) => !/^(D|use)/.test(p)) + const template = ` import { App } from 'vue' @@ -133,7 +135,7 @@ function registerInstall(pkg: any) { if ('setup' in pkg) { app.component(pkg.name, pkg) - } else if ([${packages.filter((p) => !/^(D|use)/.test(p)).join(', ')}].includes(pkg.name)) { + } else if ([${directives.length > 0 ? "'" + directives.join("', '") + "'" : ''}].includes(pkg.name)) { app.directive(pkg.name, pkg) } else { app.config.globalProperties[\`\$\${pkg.name.replace(/^use/, (c: any) => c.slice(-1).toLowerCase())}\`] = pkg -- Gitee From 937e7d59d3cc6fdf94d5a63767a181e5f6b601b0 Mon Sep 17 00:00:00 2001 From: leihaohao Date: Mon, 9 Aug 2021 11:35:23 +0800 Subject: [PATCH 3/4] =?UTF-8?q?build:=20=E5=88=9B=E5=BB=BA=20devui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加创建 devui.ts 脚本 - package.json 增加 build:devui 命令 --- package.json | 4 + scripts/create-devui.js | 187 ++++++++++++++++++++++++++++++++++++++++ yarn.lock | 11 ++- 3 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 scripts/create-devui.js diff --git a/package.json b/package.json index 39442595..6a077f51 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "app:dev": "vite", "app:build": "vite build", "build:lib": "yarn run generate:devui && vite build --config vite.config.build.ts && cp package.json dist && cp README.md dist", + "build:devui": "node scripts/create-devui", "test": "jest --config jest.config.js", "ls-lint": "ls-lint", "lint": "eslint \"{src,devui}/**/*.{vue,js,ts,jsx,tsx}\"", @@ -47,6 +48,7 @@ "@commitlint/cli": "^11.0.0", "@commitlint/config-conventional": "^11.0.0", "@ls-lint/ls-lint": "^1.10.0", + "@types/fs-extra": "^9.0.12", "@types/jest": "^26.0.23", "@typescript-eslint/eslint-plugin": "^4.27.0", "@typescript-eslint/parser": "^4.27.0", @@ -62,9 +64,11 @@ "esbuild-register": "^2.6.0", "eslint": "^7.28.0", "eslint-plugin-vue": "^7.11.1", + "fs-extra": "^10.0.0", "husky": "^4.3.7", "jest": "^27.0.4", "lint-staged": "^11.0.0", + "lodash": "^4.17.21", "sass": "^1.32.2", "shelljs": "^0.8.4", "stylelint": "^13.13.1", diff --git a/scripts/create-devui.js b/scripts/create-devui.js new file mode 100644 index 00000000..0d7c53ff --- /dev/null +++ b/scripts/create-devui.js @@ -0,0 +1,187 @@ +const fs = require('fs-extra') +const _ = require('lodash') +const { resolve, relative } = require('path') + +const DEVUI_DIR = resolve(__dirname, '../devui') +const DEVUI_DIRECTIVE_DIR = resolve(DEVUI_DIR, 'directives') +const DEVUI_FILE = resolve(DEVUI_DIR, 'vue-devui.ts') +const DEVUI_PREFIX = 'D' +const DEVUI_IGNORE_DIRS = ['shared', 'style', 'directives'] +const DEVUI_DIRECTIVE_IGNORE_DIRS = [] +const INDEX_FILE = 'index.ts' + +function bigCamelCase(str) { + return _.upperFirst(_.camelCase(str)) +} + +function getUseName(p) { + return p.startsWith('use') ? p.slice(3) : p +} + +function resolveDirFileInfo(targetDir, ignoreDirs = []) { + return fs + .readdirSync(targetDir) + .filter( + (dir) => + // 过滤:必须是目录,且不存在与忽略目录内,拥有 INDEX_FILE + fs.statSync(resolve(targetDir, dir)).isDirectory() && + !ignoreDirs.includes(dir) && + fs.existsSync(resolve(targetDir, dir, INDEX_FILE)) + ) + .map((dir) => ({ + name: DEVUI_PREFIX + bigCamelCase(dir), + dirname: dir, + path: resolve(targetDir, dir, INDEX_FILE) + })) +} + +function parseExportByFileInfo(fileInfo) { + const exportModule = {} + const componentIndexContent = fs.readFileSync(fileInfo.path, { encoding: 'utf-8' }) + + const exportRe = /export/ + const defaultRe = /export (\{[\s\n])?(\s*)default/ + const useRe = /export {([\s\n])?(\s*)use[A-Z]/ + + if (!exportRe.test(componentIndexContent)) { + return exportModule + } + + if (defaultRe.test(componentIndexContent)) { + exportModule.default = fileInfo.name + } + + if (useRe.test(componentIndexContent)) { + const useArr = [] + + let searchContent = componentIndexContent + while (searchContent.search(useRe) !== -1) { + const reStartIndex = componentIndexContent.search(useRe) + const useStartIndex = componentIndexContent.indexOf('use', reStartIndex) + const useEndIndex = componentIndexContent.indexOf('}', useStartIndex) + + const useContent = componentIndexContent.slice(useStartIndex, useEndIndex) + + useContent + .replace(/(\s|\r|\n)/g, '') + .split(',') + .forEach((use) => useArr.push(use)) + + searchContent = componentIndexContent.slice(useEndIndex) + } + + exportModule.use = useArr + } + + if (!_.isEmpty(exportModule)) { + exportModule.fileInfo = fileInfo + } + + return exportModule +} + +function createTemplate(exportModules = []) { + const packages = [] + + const importPackageStr = exportModules + .map((module) => { + const hasDefault = 'default' in module + const hasUse = 'use' in module + + const component = hasDefault ? module.default : '' + const use = hasUse ? module.use.join(', ') : '' + const relativePath = relative(DEVUI_FILE, module.fileInfo.path) + .replace(/\\/g, '/') + .replace('..', '.') + .replace('/' + INDEX_FILE, '') + + const importStr = `import ${component}${ + hasUse ? `${hasDefault ? ', {' : '{'} ${use} }` : '' + } from '${relativePath}'` + + if (hasDefault) { + packages.push(module.default) + } + + if (hasUse) { + packages.push(...module.use) + } + + return importStr + }) + .join('\n') + + const template = ` +import { App } from 'vue' + +${importPackageStr} + +${packages + .filter((p) => p.startsWith('use')) + .map((p) => `const ${getUseName(p)} = registerInstall(${p})`) + .join('\n')} + +const packages = [ + ${packages.map((p) => getUseName(p)).join(',\n ')} +].map(registerInstall) + +function registerInstall(pkg: any) { + if ('install' in pkg) return pkg + + pkg.install = function(app: App) { + if (pkg.installed) return + + if ('setup' in pkg) { + app.component(pkg.name, pkg) + } else if ([${packages.filter((p) => !/^(D|use)/.test(p)).join(', ')}].includes(pkg.name)) { + app.directive(pkg.name, pkg) + } else { + app.config.globalProperties[\`\$\${pkg.name.replace(/^use/, (c: any) => c.slice(-1).toLowerCase())}\`] = pkg + } + } + + return pkg +} + +export { + ${packages.map((p) => (p.startsWith('use') ? `${p},\n ${getUseName(p)}` : p)).join(',\n ')} +} + +export default { + version: '0.0.1', + install(app: App) { + packages.forEach((p) => app.use(p)) + } +} +` + + return template +} + +function createDevui() { + const componentFileInfo = resolveDirFileInfo(DEVUI_DIR, DEVUI_IGNORE_DIRS) + const directiveFileInfo = resolveDirFileInfo(DEVUI_DIRECTIVE_DIR, DEVUI_DIRECTIVE_IGNORE_DIRS) + const exportModules = [] + + componentFileInfo.forEach((f) => { + const em = parseExportByFileInfo(f) + + if (_.isEmpty(em)) return + + exportModules.push(em) + }) + + directiveFileInfo.forEach((f) => { + const em = parseExportByFileInfo(f) + + if (_.isEmpty(em)) return + + exportModules.push(_.update(em, 'default', (n) => n.slice(1))) + }) + + const template = createTemplate(exportModules) + + fs.writeFile(DEVUI_FILE, template, { encoding: 'utf-8' }) +} + +createDevui() diff --git a/yarn.lock b/yarn.lock index 45d6914c..f563a257 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1666,6 +1666,13 @@ resolved "https://registry.nlark.com/@types/estree/download/@types/estree-0.0.48.tgz#18dc8091b285df90db2f25aa7d906cfc394b7f74" integrity sha1-GNyAkbKF35DbLyWqfZBs/DlLf3Q= +"@types/fs-extra@^9.0.12": + version "9.0.12" + resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.12.tgz#9b8f27973df8a7a3920e8461517ebf8a7d4fdfaf" + integrity sha512-I+bsBr67CurCGnSenZZ7v94gd3tc3+Aj2taxMT4yu4ABLuOgOjeFxX3dokG24ztSRg5tnT00sL8BszO7gSMoIw== + dependencies: + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.5" resolved "https://registry.nlark.com/@types/graceful-fs/download/@types/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -3627,8 +3634,8 @@ form-data@^3.0.0: fs-extra@^10.0.0: version "10.0.0" - resolved "https://registry.nlark.com/fs-extra/download/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" - integrity sha1-n/YbZV3eU/s0qC34S7IUzoAuF8E= + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" -- Gitee From 487f257d12b628dac07d755ca702fb24ce9e4297 Mon Sep 17 00:00:00 2001 From: leihaohao Date: Mon, 9 Aug 2021 11:48:11 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/create-devui.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/create-devui.js b/scripts/create-devui.js index 0d7c53ff..b38fe3b0 100644 --- a/scripts/create-devui.js +++ b/scripts/create-devui.js @@ -111,6 +111,8 @@ function createTemplate(exportModules = []) { }) .join('\n') + const directives = packages.filter((p) => !/^(D|use)/.test(p)) + const template = ` import { App } from 'vue' @@ -133,7 +135,7 @@ function registerInstall(pkg: any) { if ('setup' in pkg) { app.component(pkg.name, pkg) - } else if ([${packages.filter((p) => !/^(D|use)/.test(p)).join(', ')}].includes(pkg.name)) { + } else if ([${directives.length > 0 ? "'" + directives.join("', '") + "'" : ''}].includes(pkg.name)) { app.directive(pkg.name, pkg) } else { app.config.globalProperties[\`\$\${pkg.name.replace(/^use/, (c: any) => c.slice(-1).toLowerCase())}\`] = pkg -- Gitee