diff --git a/internals/unplugin-tiny-vue/.npmignore b/internals/unplugin-tiny-vue/.npmignore
new file mode 100644
index 0000000000..4949f09809
--- /dev/null
+++ b/internals/unplugin-tiny-vue/.npmignore
@@ -0,0 +1 @@
+example/
\ No newline at end of file
diff --git a/internals/unplugin-tiny-vue/README.md b/internals/unplugin-tiny-vue/README.md
new file mode 100644
index 0000000000..9817107b49
--- /dev/null
+++ b/internals/unplugin-tiny-vue/README.md
@@ -0,0 +1,26 @@
+# unplugin-tiny-vue
+
+A auto import plugin. Same function as [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components).
+No import and component registration required.
+
+## Installation
+
+```bash
+npm i @opentiny/unplugin-tiny-vue -D
+
+yarn i @opentiny/unplugin-tiny-vue -D
+```
+
+## Usage
+
+vite
+
+```js
+// vite.config.js
+
+import autoImportPlugin from '@opentiny/unplugin-tiny-vue'
+
+export default {
+ plugins: [autoImportPlugin()]
+}
+```
diff --git a/internals/unplugin-tiny-vue/example/index.html b/internals/unplugin-tiny-vue/example/index.html
new file mode 100644
index 0000000000..f3845c6324
--- /dev/null
+++ b/internals/unplugin-tiny-vue/example/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Auto Import
+
+
+
+
+
+
\ No newline at end of file
diff --git a/internals/unplugin-tiny-vue/example/package.json b/internals/unplugin-tiny-vue/example/package.json
new file mode 100644
index 0000000000..aec2fa8516
--- /dev/null
+++ b/internals/unplugin-tiny-vue/example/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "my-vue-app",
+ "description": "",
+ "author": "",
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@opentiny/vue": "~3.12.1",
+ "@opentiny/vue-alert": "~3.13.0",
+ "@opentiny/vue-button-group": "~3.13.0",
+ "@opentiny/vue-icon": "^3.12.0",
+ "vue": "^3.3.9"
+ },
+ "devDependencies": {
+ "@vitejs/plugin-vue": "^4.1.0",
+ "vite": "link:../node_modules/vite",
+ "vite-plugin-inspect": "^0.8.3"
+ }
+}
diff --git a/internals/unplugin-tiny-vue/example/src/App.vue b/internals/unplugin-tiny-vue/example/src/App.vue
new file mode 100644
index 0000000000..35941f9e83
--- /dev/null
+++ b/internals/unplugin-tiny-vue/example/src/App.vue
@@ -0,0 +1,22 @@
+
+
+
+ 当前选中值:{{ checkedVal }}
+
+
+
+
+
diff --git a/internals/unplugin-tiny-vue/example/src/main.js b/internals/unplugin-tiny-vue/example/src/main.js
new file mode 100644
index 0000000000..01433bca2a
--- /dev/null
+++ b/internals/unplugin-tiny-vue/example/src/main.js
@@ -0,0 +1,4 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+
+createApp(App).mount('#app')
diff --git a/internals/unplugin-tiny-vue/example/vite.config.js b/internals/unplugin-tiny-vue/example/vite.config.js
new file mode 100644
index 0000000000..115c877802
--- /dev/null
+++ b/internals/unplugin-tiny-vue/example/vite.config.js
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import Inspect from 'vite-plugin-inspect'
+import autoImportPlugin from '../dist/index.js'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [vue(), Inspect(), autoImportPlugin()],
+ define: {
+ 'process.env': { ...process.env, TINY_MODE: 'pc' }
+ },
+ resolve: {
+ extensions: ['.js', '.jsx', '.vue', '.ts']
+ }
+})
diff --git a/internals/unplugin-tiny-vue/package.json b/internals/unplugin-tiny-vue/package.json
new file mode 100644
index 0000000000..78adefca12
--- /dev/null
+++ b/internals/unplugin-tiny-vue/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "@opentiny/unplugin-tiny-vue",
+ "version": "1.0.0",
+ "description": "A vite auto import plugin for TinyVue",
+ "main": "dist/index.cjs",
+ "module": "dist/index.js",
+ "typings": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "require": "./dist/index.cjs",
+ "import": "./dist/index.js",
+ "types": "./dist/index.d.ts"
+ }
+ },
+ "scripts": {
+ "dev": "pnpm run build --watch --ignore-watch example",
+ "build": "rimraf dist && tsup src/index.ts --dts --format cjs,esm",
+ "prepublishOnly": "pnpm build"
+ },
+ "type": "module",
+ "types": "dist/index.d.ts",
+ "author": "Tiny Vue Team",
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:opentiny/tiny-vue.git"
+ },
+ "keywords": [
+ "vite-plugin",
+ "TinyVue",
+ "vite",
+ "auto-import"
+ ],
+ "license": "MIT",
+ "peerDependencies": {
+ "vite": ">=4"
+ },
+ "dependencies": {
+ "magic-string": "^0.27.0"
+ },
+ "devDependencies": {
+ "rimraf": "^5.0.5",
+ "tsup": "7.2.0",
+ "typescript": "^5.0.0",
+ "vite": "^4.3.8"
+ }
+}
diff --git a/internals/unplugin-tiny-vue/src/index.ts b/internals/unplugin-tiny-vue/src/index.ts
new file mode 100644
index 0000000000..7405f5d206
--- /dev/null
+++ b/internals/unplugin-tiny-vue/src/index.ts
@@ -0,0 +1,62 @@
+import MagicString from 'magic-string'
+import type { Plugin } from 'vite'
+
+function pascalCase(str: string) {
+ const camelCaseStr = str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ''))
+ return camelCaseStr.charAt(0).toUpperCase() + camelCaseStr.slice(1)
+}
+
+const resolveVue = (code: string, s: MagicString) => {
+ const results: any = []
+
+ for (const match of code.matchAll(/_resolveComponent[0-9]*\("(.+?)"\)/g)) {
+ const matchedName = match[1]
+ if (match.index != null && matchedName && !matchedName.startsWith('_')) {
+ const start = match.index
+ const end = start + match[0].length
+ results.push({
+ rawName: matchedName,
+ replace: (resolved: string) => s.overwrite(start, end, resolved)
+ })
+ }
+ }
+
+ return results
+}
+
+const findComponent = (rawName: string, name: string, s: MagicString) => {
+ if (!name.match(/^Tiny[a-zA-Z]/)) {
+ return
+ }
+ s.prepend(`import ${name} from '@opentiny/vue-${rawName.slice(5)}';\n`)
+}
+
+const transformCode = (code) => {
+ const s = new MagicString(code)
+ const results = resolveVue(code, s)
+
+ for (const { rawName, replace } of results) {
+ const name = pascalCase(rawName)
+ findComponent(rawName, name, s)
+ replace(name)
+ }
+
+ const result = s.toString()
+ return result
+}
+
+export default function vitePluginAutoImport(): Plugin {
+ return {
+ name: '@opentiny/auto-import',
+
+ transform(code, id) {
+ // 不处理node_modules内的依赖
+ if (/\.(?:vue)$/.test(id) && !/(node_modules)/.test(id)) {
+ return {
+ code: transformCode(code),
+ map: null
+ }
+ }
+ }
+ }
+}
diff --git a/internals/unplugin-tiny-vue/tsconfig.json b/internals/unplugin-tiny-vue/tsconfig.json
new file mode 100644
index 0000000000..83db8d40db
--- /dev/null
+++ b/internals/unplugin-tiny-vue/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "module": "ESNext",
+ "target": "esnext",
+ "moduleResolution": "node",
+ "strict": true,
+ "declaration": true,
+ "noUnusedLocals": true,
+ "esModuleInterop": true,
+ "outDir": "dist",
+ "lib": [
+ "ESNext"
+ ],
+ "sourceMap": false,
+ "noEmitOnError": true,
+ "noImplicitAny": false
+ },
+ "include": [
+ "src/*",
+ "*.d.ts"
+ ],
+ "exclude": [
+ "dist",
+ "node_modules"
+ ]
+}
\ No newline at end of file