From e391a0b77f67f633c30f1451c185f6cd2f694d08 Mon Sep 17 00:00:00 2001
From: however <102494131+river-xiu@users.noreply.github.com>
Date: Mon, 29 Apr 2024 17:30:39 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E9=80=82=E9=85=8D=20solidjs=20(#1566)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat:同步代码
* chore: 优化本地 svg 加载
---
examples/solid-demo/index.html | 13 +
examples/solid-demo/package.json | 24 ++
examples/solid-demo/public/vite.svg | 1 +
examples/solid-demo/src/App.tsx | 35 +++
examples/solid-demo/src/main.css | 4 +
examples/solid-demo/src/main.tsx | 7 +
examples/solid-demo/tsconfig.json | 25 ++
examples/solid-demo/tsconfig.node.json | 10 +
examples/solid-demo/vite.config.ts | 10 +
examples/solid-docs/package.json | 15 +-
examples/solid-docs/src/App.tsx | 50 +++-
examples/solid-docs/src/main.less | 17 ++
examples/solid-docs/src/main.tsx | 1 -
examples/solid-docs/src/views/alert.tsx | 61 ++++
examples/solid-docs/src/views/button.tsx | 60 ++++
examples/solid-docs/src/views/icon.less | 6 +
examples/solid-docs/src/views/icon.tsx | 20 ++
examples/solid-docs/src/views/switch.tsx | 25 ++
examples/solid-docs/vite.config.ts | 15 +-
.../cli/src/commands/build/build-ui-solid.ts | 278 ++++++++++++++++++
internals/cli/src/commands/build/index.ts | 1 +
internals/vite-plugin-template2jsx/README.md | 3 +
internals/vite-plugin-template2jsx/index.js | 143 +++++++++
.../vite-plugin-template2jsx/package.json | 28 ++
.../vite-plugin-template2jsx/src/helpers.js | 222 ++++++++++++++
.../vite-plugin-template2jsx/src/plugin.js | 95 ++++++
.../vite-plugin-template2jsx/src/render.js | 276 +++++++++++++++++
.../template/index.tss | 3 +
.../template/package.jsons | 17 ++
.../template/src/index.tss | 11 +
.../template/src/pc.jsxs | 15 +
package.json | 6 +-
packages/solid/index.ts | 6 +-
packages/solid/package.json | 5 +-
packages/solid/src/common/package.json | 2 +-
packages/solid/src/common/src/index.ts | 173 ++++++++---
pnpm-workspace.yaml | 1 +
tsconfig.solid.json | 30 ++
38 files changed, 1654 insertions(+), 60 deletions(-)
create mode 100644 examples/solid-demo/index.html
create mode 100644 examples/solid-demo/package.json
create mode 100644 examples/solid-demo/public/vite.svg
create mode 100644 examples/solid-demo/src/App.tsx
create mode 100644 examples/solid-demo/src/main.css
create mode 100644 examples/solid-demo/src/main.tsx
create mode 100644 examples/solid-demo/tsconfig.json
create mode 100644 examples/solid-demo/tsconfig.node.json
create mode 100644 examples/solid-demo/vite.config.ts
create mode 100644 examples/solid-docs/src/main.less
create mode 100644 examples/solid-docs/src/views/alert.tsx
create mode 100644 examples/solid-docs/src/views/button.tsx
create mode 100644 examples/solid-docs/src/views/icon.less
create mode 100644 examples/solid-docs/src/views/icon.tsx
create mode 100644 examples/solid-docs/src/views/switch.tsx
create mode 100644 internals/cli/src/commands/build/build-ui-solid.ts
create mode 100644 internals/vite-plugin-template2jsx/README.md
create mode 100644 internals/vite-plugin-template2jsx/index.js
create mode 100644 internals/vite-plugin-template2jsx/package.json
create mode 100644 internals/vite-plugin-template2jsx/src/helpers.js
create mode 100644 internals/vite-plugin-template2jsx/src/plugin.js
create mode 100644 internals/vite-plugin-template2jsx/src/render.js
create mode 100644 internals/vite-plugin-template2jsx/template/index.tss
create mode 100644 internals/vite-plugin-template2jsx/template/package.jsons
create mode 100644 internals/vite-plugin-template2jsx/template/src/index.tss
create mode 100644 internals/vite-plugin-template2jsx/template/src/pc.jsxs
create mode 100644 tsconfig.solid.json
diff --git a/examples/solid-demo/index.html b/examples/solid-demo/index.html
new file mode 100644
index 000000000..b9a46f405
--- /dev/null
+++ b/examples/solid-demo/index.html
@@ -0,0 +1,13 @@
+
+
+
+
-
+
+
+
+ {(item) => (
+ <>
+
+ {item}
+
+ /
+ >
+ )}
+
+
+
+
)
}
diff --git a/examples/solid-docs/src/main.less b/examples/solid-docs/src/main.less
new file mode 100644
index 000000000..3ce3f8120
--- /dev/null
+++ b/examples/solid-docs/src/main.less
@@ -0,0 +1,17 @@
+.app {
+ margin: 40px auto;
+ width: 640px;
+
+ a.title {
+ color: #39f;
+ cursor: pointer;
+ display: inline-block;
+ margin:0 10px;
+ text-decoration: none;
+
+ &.active {
+ font-weight: 600;
+ text-decoration: underline;
+ }
+ }
+}
diff --git a/examples/solid-docs/src/main.tsx b/examples/solid-docs/src/main.tsx
index 2cda43153..0b2a3123a 100644
--- a/examples/solid-docs/src/main.tsx
+++ b/examples/solid-docs/src/main.tsx
@@ -1,6 +1,5 @@
import { render } from 'solid-js/web'
import App from './App'
-import './main.css'
const root = document.getElementById('root')
diff --git a/examples/solid-docs/src/views/alert.tsx b/examples/solid-docs/src/views/alert.tsx
new file mode 100644
index 000000000..9affe1fef
--- /dev/null
+++ b/examples/solid-docs/src/views/alert.tsx
@@ -0,0 +1,61 @@
+import TinyAlert from '@opentiny/vue-alert'
+
+export default function () {
+ const alertSlots = {
+ title:
插槽标题
+ }
+
+ const alertSlots2 = {
+ description: (
+
+ 插槽描述
+
+ )
+ }
+
+ const alertSlots3 = {
+ close:
插槽关闭
+ }
+
+ return (
+
+ )
+}
diff --git a/examples/solid-docs/src/views/button.tsx b/examples/solid-docs/src/views/button.tsx
new file mode 100644
index 000000000..a01ab44e5
--- /dev/null
+++ b/examples/solid-docs/src/views/button.tsx
@@ -0,0 +1,60 @@
+import { createMutable } from 'solid-js/store'
+import TinyButton from '@opentiny/vue-button'
+import TinyIconSearch from '@opentiny/vue-icon/search/index.ts'
+
+export default function () {
+ const state = createMutable({
+ value: 1
+ })
+ const hanleClick = () => {
+ state.value++
+ }
+
+ return (
+
+ 默认按钮
+ 主要按钮
+ 成功按钮
+
+
+ 信息按钮
+ 警告按钮
+ 危险按钮
+
+
+ 朴素按钮
+
+
+ 加载中
+
+
+
+
+
+ 纯文本按钮
+
+
+
+ {' '}
+ 超大按钮{' '}
+
+
+ {' '}
+ 中等按钮{' '}
+
+
+ {' '}
+ 小型按钮{' '}
+
+
+ {' '}
+ 超小按钮{' '}
+
+
+
+ 点击事件 点击计数:{state.value}
+
+
+
+ )
+}
diff --git a/examples/solid-docs/src/views/icon.less b/examples/solid-docs/src/views/icon.less
new file mode 100644
index 000000000..89f631e06
--- /dev/null
+++ b/examples/solid-docs/src/views/icon.less
@@ -0,0 +1,6 @@
+.icon-demo .tiny-svg {
+ fill: #8994aa;
+ margin: 20px 50px;
+ vertical-align: middle;
+ font-size: 48px;
+}
\ No newline at end of file
diff --git a/examples/solid-docs/src/views/icon.tsx b/examples/solid-docs/src/views/icon.tsx
new file mode 100644
index 000000000..d6d61677f
--- /dev/null
+++ b/examples/solid-docs/src/views/icon.tsx
@@ -0,0 +1,20 @@
+import TinyIconActivation from '@opentiny/vue-icon/activation/index.ts'
+import TinyIconShare from '@opentiny/vue-icon/share/index.ts'
+import TinyIconDel from '@opentiny/vue-icon/del/index.ts'
+import TinyIconWriting from '@opentiny/vue-icon/writing/index.ts'
+import TinyIconAscending from '@opentiny/vue-icon/ascending/index.ts'
+import TinyIconClockWork from '@opentiny/vue-icon/clock-work/index.ts'
+import './icon.less'
+
+export default function () {
+ return (
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/examples/solid-docs/src/views/switch.tsx b/examples/solid-docs/src/views/switch.tsx
new file mode 100644
index 000000000..d20d5411b
--- /dev/null
+++ b/examples/solid-docs/src/views/switch.tsx
@@ -0,0 +1,25 @@
+import TinySwitch from '@opentiny/vue-switch'
+import { createMutable } from 'solid-js/store'
+
+export default function () {
+ const state = createMutable({
+ value: true
+ })
+
+ const switchSlots = {
+ open:
打开,
+ close:
关闭
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/examples/solid-docs/vite.config.ts b/examples/solid-docs/vite.config.ts
index 163b240eb..74c335d03 100644
--- a/examples/solid-docs/vite.config.ts
+++ b/examples/solid-docs/vite.config.ts
@@ -1,7 +1,18 @@
import { defineConfig } from 'vite'
import solid from 'vite-plugin-solid'
-import svgr from 'vite-plugin-svgr'
+import path from 'node:path'
+import inspectPlugin from 'vite-plugin-inspect'
+import vueTemplate2jsx from '@opentiny/vue-vite-template2jsx'
export default defineConfig({
- plugins: [solid(), svgr()]
+ plugins: [inspectPlugin(), vueTemplate2jsx(), solid({ extensions: ['.js', '.ts', '.tsx', '.jsx', '.vue'] })],
+ define: {
+ 'process.env': {}
+ },
+ resolve: {
+ alias: {
+ '@': path.resolve('./src'),
+ '@opentiny/solid-common': path.resolve('../../packages/solid/src/common/src/index.ts')
+ }
+ }
})
diff --git a/internals/cli/src/commands/build/build-ui-solid.ts b/internals/cli/src/commands/build/build-ui-solid.ts
new file mode 100644
index 000000000..c727fd49f
--- /dev/null
+++ b/internals/cli/src/commands/build/build-ui-solid.ts
@@ -0,0 +1,278 @@
+import { getBabelOutputPlugin } from '@rollup/plugin-babel'
+import { createRequire } from 'node:module'
+import path from 'node:path'
+import { build, defineConfig } from 'vite'
+import { getAlias, pathFromWorkspaceRoot } from '../../config/vite'
+import { external } from '../../shared/config'
+import type { Module } from '../../shared/module-utils'
+import { getAllIcons, getAllModules, getByName } from '../../shared/module-utils'
+import { logGreen, kebabCase, capitalizeKebabCase, getPatchVersion, isValidVersion } from '../../shared/utils'
+import generatePackageJsonPlugin from './rollup/generate-package-json'
+import inlineChunksPlugin from './rollup/inline-chunks'
+import replaceModuleNamePlugin from './rollup/replace-module-name'
+import solid from 'vite-plugin-solid'
+import vueTemplate2jsx from '@opentiny/vue-vite-template2jsx'
+
+export const pathFromPackages = (...args) => pathFromWorkspaceRoot('packages', ...args)
+export const require = createRequire(import.meta.url)
+export const requireModules = (id: string) => require(require.resolve(pathFromWorkspaceRoot(id)))
+
+// 需要打包的solid组件
+const buildComponents = ['alert', 'button']
+
+export interface BaseConfig {
+ buildTarget: string
+ npmScope?: string
+}
+
+export const getBaseConfig = ({ buildTarget }: BaseConfig) => {
+ const versionTarget = isValidVersion(buildTarget) ? buildTarget : `3.${buildTarget}`
+ const themeAndRenderlessVersion = isValidVersion(buildTarget) ? buildTarget : `3.${buildTarget}`
+ const isThemeOrRenderless = (key) => key.includes('@opentiny/vue-theme') || key.includes('@opentiny/vue-renderless')
+
+ return defineConfig({
+ publicDir: false,
+ plugins: [
+ inlineChunksPlugin({ deleteInlinedFiles: true }),
+ generatePackageJsonPlugin({
+ beforeWriteFile: (filePath, content) => {
+ const dependencies = {}
+
+ Object.entries(content.dependencies).forEach(([key, value]) => {
+ // dependencies里的@opentiny,统一使用:~x.x.0
+ if (isThemeOrRenderless(key)) {
+ dependencies[key] = getPatchVersion(themeAndRenderlessVersion)
+ } else if ((value as string).includes('workspace:~')) {
+ dependencies[
+ key.replace('@opentiny/vue', '@opensolidtiny/solid').replace('@opentiny/solid', '@opensolidtiny/solid')
+ ] = getPatchVersion(versionTarget)
+ } else {
+ dependencies[key] = value
+ }
+ })
+
+ const matchList = ['solid-icon', 'vue-icon-saas', 'solid']
+
+ // 如果是主入口、svg图标或者主题规范包则直接指向相同路径
+ if (matchList.includes(filePath)) {
+ content.main = './index.js'
+ content.module = './index.js'
+ } else {
+ content.main = './lib/index.js'
+ content.module = './lib/index.js'
+ }
+
+ content.name = content.name
+ .replace('@opentiny/vue', '@opensolidtiny/solid')
+ .replace('@opentiny/solid', '@opensolidtiny/solid')
+ content.version = versionTarget
+ content.dependencies = dependencies
+
+ delete content.devDependencies
+ delete content.private
+ delete content.exports
+
+ return {
+ filePath: filePath.replace(/[\\/]lib$/, ''),
+ content
+ }
+ }
+ }),
+ replaceModuleNamePlugin(versionTarget),
+ vueTemplate2jsx(),
+ solid({ extensions: ['.js', '.ts', '.tsx', '.jsx', '.vue'] })
+ ],
+ resolve: {
+ extensions: ['.js', '.ts', '.tsx', '.vue'],
+ alias: {
+ ...getAlias(3, '', '')
+ }
+ },
+ define: {
+ 'process.env.BUILD_TARGET': JSON.stringify('component')
+ }
+ })
+}
+
+async function batchBuildAll({ tasks, formats, message, emptyOutDir, buildTarget, npmScope }) {
+ const rootDir = pathFromPackages('')
+ const outDir = path.resolve(rootDir, `dist-solid/${npmScope}`)
+ await batchBuild({
+ tasks,
+ formats,
+ message,
+ emptyOutDir
+ })
+
+ function toEntry(libs) {
+ return libs.reduce((result, { libPath, path: file }) => {
+ const tLibPath = libPath.replace('-lib/', '/lib/')
+ result[tLibPath] = pathFromPackages(file)
+ return result
+ }, {})
+ }
+
+ async function batchBuild({ tasks, formats, message, emptyOutDir }) {
+ if (tasks.length === 0) return
+ logGreen(`====== 开始构建 ${message} ======`)
+ const entry = toEntry(tasks)
+
+ await build({
+ configFile: false,
+ ...getBaseConfig({ buildTarget }),
+ build: {
+ emptyOutDir,
+ minify: false,
+ rollupOptions: {
+ plugins: [
+ getBabelOutputPlugin({
+ presets: [['@babel/preset-env', { loose: true, modules: false }]]
+ }) as any
+ ],
+ external: (source, importer, isResolved) => {
+ // vite打包入口文件或者没有解析过得包不能排除依赖
+ if (isResolved || !importer) {
+ return false
+ }
+
+ if (/vue-icon(-saas)?\/index/.test(importer)) {
+ // 图标入口排除子图标
+ return /^\.\//.test(source)
+ }
+
+ // 子图标排除周边引用, 这里注意不要排除svg图标
+ if (/vue-icon(-saas)?\/.+\/index/.test(importer)) {
+ return !/\.svg/.test(source)
+ }
+
+ if (/src\/index/.test(importer)) {
+ // 模块入口,pc/mobile 文件要分离,同时排除 node_modules 依赖
+ return /^\.\/(pc|mobile|mobile-first)/.test(source) || external(source)
+ }
+
+ // @opentiny/vue 总入口,需要排除所有依赖
+ if (/vue\/(index|pc|mobile|mobile-first)\.ts$/.test(importer)) {
+ return true
+ }
+
+ return external(source)
+ },
+ output: {
+ strict: false,
+ manualChunks: {}
+ }
+ },
+ lib: {
+ // 这里可以多入口打包,也可以单入口打包
+ entry,
+ formats,
+ fileName: (format, entryName) => `${entryName}.js`
+ },
+ outDir
+ }
+ })
+ }
+}
+
+export interface BuildUiOption {
+ buildTarget: string // 目标版本,必填, 不需要major位,因为需要同时打出vue2和vue3的包
+ formats: string[] // 打包的格式
+ clean: boolean // 是否清空build产物
+ scope?: string // npm的组织名称
+ min?: boolean // 是否压缩产物
+}
+
+function getEntryTasks(): Module[] {
+ // 读取TinyVue组件库入口文件
+ return [
+ {
+ path: `solid/index.ts`,
+ libPath: `solid/index`,
+ type: 'module',
+ name: kebabCase({ str: '@opensolidtiny/solid' }),
+ global: capitalizeKebabCase('opentinySolid'),
+ importName: '@opensolidtiny/solid'
+ }
+ ]
+}
+
+function getSolidCommonTasks(): Module[] {
+ // 读取TinyVue组件库入口文件
+ return [
+ {
+ path: `solid/src/common/src/index.ts`,
+ libPath: `common/lib/index`,
+ type: 'module',
+ name: kebabCase({ str: '@opensolidtiny/solid-common' }),
+ global: capitalizeKebabCase('opentinySolidCommon'),
+ importName: '@opensolidtiny/solid-common'
+ }
+ ]
+}
+
+function getTasks(names: string[]): Module[] {
+ // 没有指定组件,则全量构建
+ if (names.length === 0) {
+ return [...getAllModules(false)]
+ }
+
+ return names
+ .map((name) =>
+ getByName({
+ name: kebabCase({ str: name.replace('@opentiny/vue-', '') }),
+ isSort: false
+ })
+ )
+ .flat()
+}
+
+/**
+ * TinyVue组件打包主入口
+ * @private
+ * @param {string[]} names 需要打包的名字,如果不传默认打包全量组件 例如只打包alert和button两个组件 pnpm build:ui alert button
+ * @param {BuildUiOption} buildUiOption 具体参数参考BuildUiOption接口
+ */
+
+export async function buildSolid(
+ names: string[] = [],
+ { buildTarget = '3.14.0', formats = ['es'], clean = false, scope = '@opensolidtiny' }: BuildUiOption
+) {
+ // 是否清空构建目录
+ let emptyOutDir = clean
+ // 要构建的模块
+ let tasks = getTasks(names).filter((item) => !item.path.includes('mobile'))
+
+ // 如果指定了打包icon或者没有传入任何组件
+ if (names.some((name) => name.includes('icon')) || !names.length) {
+ const icons = getAllIcons()
+ icons.forEach((item) => {
+ item.libPath = item.libPath.replace('vue-icon', 'solid-icon')
+ })
+
+ tasks.push(...icons)
+ }
+
+ // 过虑出需要打包的solid组件入口
+ tasks = tasks
+ .filter((item) =>
+ buildComponents.some((value) => item.path.includes(`/${value}/`) || item.path.includes('vue-icon'))
+ )
+ .filter((item) => !item.path.includes('icon-saas'))
+
+ tasks.forEach((item) => {
+ if (item.libPath.includes('vue-icon')) {
+ item.libPath = item.libPath.replace('vue-icon', 'solid-icon')
+ }
+ })
+
+ // 打包入口文件
+ if (names.length === 0 || names.some((name) => ['@opensolidtiny/solid', 'solid'].includes(name))) {
+ tasks.push(...getEntryTasks(), ...getSolidCommonTasks())
+ }
+
+ // 要构建的vue框架版本
+ const message = `TINY for solid: ${JSON.stringify(names.length ? names : '全量')}`
+ await batchBuildAll({ tasks, formats, message, emptyOutDir, buildTarget, npmScope: scope })
+ // 确保只运行一次
+ emptyOutDir = false
+}
diff --git a/internals/cli/src/commands/build/index.ts b/internals/cli/src/commands/build/index.ts
index f06f18494..f6b269854 100644
--- a/internals/cli/src/commands/build/index.ts
+++ b/internals/cli/src/commands/build/index.ts
@@ -4,3 +4,4 @@ export * from './build-runtime'
export * from './build-ui-react'
export * from './build-entry-react'
export * from './build-chart-theme'
+export * from './build-ui-solid'
diff --git a/internals/vite-plugin-template2jsx/README.md b/internals/vite-plugin-template2jsx/README.md
new file mode 100644
index 000000000..2a00fbc5f
--- /dev/null
+++ b/internals/vite-plugin-template2jsx/README.md
@@ -0,0 +1,3 @@
+# vue-vite-template2jsx
+
+## 一个可以将vue模板转化成jsx语法的vite插件
diff --git a/internals/vite-plugin-template2jsx/index.js b/internals/vite-plugin-template2jsx/index.js
new file mode 100644
index 000000000..dfe10ff93
--- /dev/null
+++ b/internals/vite-plugin-template2jsx/index.js
@@ -0,0 +1,143 @@
+import { createRequire } from 'node:module'
+import { readFileSync, existsSync } from 'node:fs'
+import { transformVueTemplateToSolid } from './src/plugin.js'
+import { dirname } from 'node:path'
+import { fileURLToPath } from 'node:url'
+import path from 'node:path'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = dirname(__filename)
+
+const require = createRequire(import.meta.url)
+
+const indexTemplatePath = path.resolve(__dirname, './template/src/index.tss')
+const pcTemplatePath = path.resolve(__dirname, './template/src/pc.jsxs')
+
+// 多模板入口模板
+const indexTemplate = readFileSync(indexTemplatePath, { encoding: 'utf-8' })
+
+// PC模板入口
+const pcTemplate = readFileSync(pcTemplatePath, { encoding: 'utf-8' })
+
+const matchComponentRegx = /vue\/src\/([a-z]+)\/src/
+
+const fundProps = (code, findStr) => {
+ let findIndex = code.indexOf(findStr)
+ let props = ''
+
+ if (~findIndex) {
+ const endStr = 'export '
+ let constantsPart = code.substring(findIndex + findStr.length, code.length)
+ props = constantsPart.substring(0, constantsPart.indexOf(endStr))
+ }
+
+ return props
+}
+
+const getSvgContent = (svg) => {
+ return svg.substring(svg.indexOf('>') + 1, svg.length)
+}
+
+const getDefaultValueFromEntry = (id) => {
+ const componentMatchs = id.match(matchComponentRegx)
+ const entryPath = id.replace('pc.vue', 'index.ts')
+ if (existsSync(entryPath)) {
+ if (componentMatchs?.[1]) {
+ const code = readFileSync(entryPath, { encoding: 'utf-8' })
+ let constants = fundProps(code, '$constants =') || '{}'
+ let propsContent = fundProps(code, 'Props =') || fundProps(code, 'props :')
+ let props = {}
+
+ if (propsContent) {
+ const propsContentParts = propsContent.split(/\n/)
+ propsContentParts.forEach((item, index) => {
+ if (item.indexOf('type:') && ['Boolean', 'String', 'Number'].some((type) => item.includes(type))) {
+ const name = propsContentParts[index - 1].replace(/\W/g, '')
+ let value = propsContentParts[index + 1]
+
+ if (name && value.includes('default:')) {
+ const type = /['"]/.test(value) ? 'Char' : 'Other'
+ value = value.replace('default:', '').replace(/["|'|\s,]/g, '')
+ props[name] = { type, value }
+ }
+ }
+ })
+ }
+
+ return {
+ $constants: constants,
+ $props: props
+ }
+ }
+ }
+
+ return {
+ $constants: '{}',
+ $props: {}
+ }
+}
+
+export default function vueTemplate2Jsx() {
+ return {
+ name: '@opentiny/vue-vite-template2jsx',
+ enforce: 'pre',
+ transform(code, id) {
+ if (id.includes('vue-icon/src')) {
+ const svgName = code.match(/([a-z1-9-]+)\.svg/)
+
+ if (svgName && svgName[0]) {
+ let svgPath
+
+ try {
+ svgPath = require.resolve(`@opentiny/vue-theme/svgs/${svgName[0]}`)
+ } catch (e) {
+ svgPath = path.resolve(__dirname, `../../packages/theme/src/svgs/${svgName[0]}`)
+ }
+
+ if (existsSync(svgPath)) {
+ let svgContent = readFileSync(svgPath, { encoding: 'utf-8' })
+
+ if (svgContent.includes('/, '')
+ }
+
+ if (svgContent.includes('/, '')
+ }
+
+ const viewBox = svgContent.match(/viewBox="[\d|\s]+"/)?.[0] || `viewBox="0 0 24 24"`
+
+ return `export default function(props) {
+ return (