diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c4c30b5592..79a4d11b1b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19230,7 +19230,3 @@ packages:
which: 3.0.1
yaml: 2.3.4
dev: true
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
diff --git a/suites/boilerplate/src/index.ts b/suites/boilerplate/src/index.ts
index 88d359f8e3..8a1feabf77 100644
--- a/suites/boilerplate/src/index.ts
+++ b/suites/boilerplate/src/index.ts
@@ -47,6 +47,7 @@ export default async ({
choices: [
{ title: 'Static Site', value: 'site' },
{ title: 'React Library', value: 'react' },
+ { title: 'Vue Library', value: 'vue' },
{ title: 'Theme Package', value: 'theme' },
],
initial: 0,
@@ -75,6 +76,7 @@ export default async ({
const descriptions = {
site: 'A static site based on dumi',
react: 'A react library developed with dumi',
+ vue: 'A vue library developed with dumi',
theme: 'A theme package for dumi',
};
const questions: prompts.PromptObject[] = [
@@ -125,6 +127,16 @@ export default async ({
return 'NPM package name is required';
},
});
+ } else if (type === 'vue') {
+ questions.unshift({
+ name: 'name',
+ type: 'text',
+ message: 'Input NPM package name',
+ validate: (value: string) => {
+ if (value && value.trim()) return true;
+ return 'NPM package name is required';
+ },
+ });
}
const generator = new BaseGenerator({
diff --git a/suites/boilerplate/templates/vue/.dumirc.ts.tpl b/suites/boilerplate/templates/vue/.dumirc.ts.tpl
new file mode 100644
index 0000000000..e9a0609a0f
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.dumirc.ts.tpl
@@ -0,0 +1,13 @@
+import { defineConfig } from 'dumi';
+
+export default defineConfig({
+ apiParser: {},
+ resolve: {
+ entryFile: 'src/index.ts',
+ },
+ outputPath: 'docs-dist',
+ themeConfig: {
+ name: '{{{ name }}}',
+ },
+ presets: [require.resolve('@dumijs/preset-vue')],
+});
diff --git a/suites/boilerplate/templates/vue/.editorconfig b/suites/boilerplate/templates/vue/.editorconfig
new file mode 100644
index 0000000000..e717f5eb63
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.editorconfig
@@ -0,0 +1,13 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/suites/boilerplate/templates/vue/.eslintrc.js b/suites/boilerplate/templates/vue/.eslintrc.js
new file mode 100644
index 0000000000..f5711b2db8
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.eslintrc.js
@@ -0,0 +1,13 @@
+module.exports = {
+ extends: ['plugin:vue/vue3-recommended'],
+ parser: 'vue-eslint-parser',
+ parserOptions: {
+ parser: '@typescript-eslint/parser',
+ sourceType: 'module',
+ ecmaVersion: 2020,
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ rules: {},
+};
diff --git a/suites/boilerplate/templates/vue/.gitignore.tpl b/suites/boilerplate/templates/vue/.gitignore.tpl
new file mode 100644
index 0000000000..8df3240707
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.gitignore.tpl
@@ -0,0 +1,7 @@
+node_modules
+/dist
+.dumi/tmp
+.dumi/tmp-test
+.dumi/tmp-production
+.DS_Store
+/coverage
diff --git a/suites/boilerplate/templates/vue/.husky/commit-msg b/suites/boilerplate/templates/vue/.husky/commit-msg
new file mode 100755
index 0000000000..5b0b35410a
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.husky/commit-msg
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+. "$(dirname -- "$0")/_/husky.sh"
+
+npx commitlint --edit "${1}"
diff --git a/suites/boilerplate/templates/vue/.husky/pre-commit b/suites/boilerplate/templates/vue/.husky/pre-commit
new file mode 100755
index 0000000000..d24fdfc601
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.husky/pre-commit
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+. "$(dirname -- "$0")/_/husky.sh"
+
+npx lint-staged
diff --git a/suites/boilerplate/templates/vue/.prettierignore b/suites/boilerplate/templates/vue/.prettierignore
new file mode 100644
index 0000000000..6a50e206c7
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.prettierignore
@@ -0,0 +1,2 @@
+/dist
+*.yaml
diff --git a/suites/boilerplate/templates/vue/.prettierrc.js b/suites/boilerplate/templates/vue/.prettierrc.js
new file mode 100644
index 0000000000..e6df093da7
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.prettierrc.js
@@ -0,0 +1,19 @@
+module.exports = {
+ pluginSearchDirs: false,
+ plugins: [
+ require.resolve('prettier-plugin-organize-imports'),
+ require.resolve('prettier-plugin-packagejson'),
+ ],
+ printWidth: 80,
+ proseWrap: 'never',
+ singleQuote: true,
+ trailingComma: 'all',
+ overrides: [
+ {
+ files: '*.md',
+ options: {
+ proseWrap: 'preserve',
+ },
+ },
+ ],
+};
diff --git a/suites/boilerplate/templates/vue/.stylelintrc b/suites/boilerplate/templates/vue/.stylelintrc
new file mode 100644
index 0000000000..e3621944ff
--- /dev/null
+++ b/suites/boilerplate/templates/vue/.stylelintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "@umijs/lint/dist/config/stylelint"
+}
diff --git a/suites/boilerplate/templates/vue/LICENSE.tpl b/suites/boilerplate/templates/vue/LICENSE.tpl
new file mode 100644
index 0000000000..1b77645ee5
--- /dev/null
+++ b/suites/boilerplate/templates/vue/LICENSE.tpl
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) {{{ author }}}
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/suites/boilerplate/templates/vue/README.md.tpl b/suites/boilerplate/templates/vue/README.md.tpl
new file mode 100644
index 0000000000..9f1b5782ce
--- /dev/null
+++ b/suites/boilerplate/templates/vue/README.md.tpl
@@ -0,0 +1,64 @@
+# {{{ name }}}
+
+[![NPM version](https://img.shields.io/npm/v/{{{ name }}}.svg?style=flat)](https://npmjs.org/package/{{{ name }}})
+[![NPM downloads](http://img.shields.io/npm/dm/{{{ name }}}.svg?style=flat)](https://npmjs.org/package/{{{ name }}})
+
+{{{ description }}}
+
+## Usage
+
+First, introduce css file:
+
+```ts
+import '{{ name }}/dist/style.css';
+```
+
+Then, introduce components:
+
+```html
+
+```
+
+## Options
+
+TODO
+
+## Development
+
+```bash
+# install dependencies
+$ {{ npmClient }} install
+
+# develop library by docs demo
+$ {{ npmClient }} start
+
+# build library source code
+$ {{ npmClient }} run build
+
+# build library source code in watch mode
+$ {{ npmClient }} run build:watch
+
+# build docs
+$ {{ npmClient }} run docs:build
+
+# Locally preview the production build.
+$ {{ npmClient }} run docs:preview
+
+# check your project for potential problems
+$ {{ npmClient }} run doctor
+
+# Test
+$ {{ npmClient }} test
+
+# Coverage
+$ {{ npmClient }} test:cov
+
+# Lint
+$ {{ npmClient }} lint
+```
+
+## LICENSE
+
+MIT
diff --git a/suites/boilerplate/templates/vue/docs/guide.md b/suites/boilerplate/templates/vue/docs/guide.md
new file mode 100644
index 0000000000..5504ddf6ab
--- /dev/null
+++ b/suites/boilerplate/templates/vue/docs/guide.md
@@ -0,0 +1 @@
+This is a guide example.
diff --git a/suites/boilerplate/templates/vue/docs/index.md.tpl b/suites/boilerplate/templates/vue/docs/index.md.tpl
new file mode 100644
index 0000000000..c9aba4e652
--- /dev/null
+++ b/suites/boilerplate/templates/vue/docs/index.md.tpl
@@ -0,0 +1,22 @@
+---
+hero:
+ title: library
+ description: {{{ description }}}
+ actions:
+ - text: Hello
+ link: /
+ - text: Vue
+ link: /
+features:
+ - title: Hello
+ emoji: 💎
+ description: Put hello description here
+ - title: Vue
+ emoji: 🌈
+ description: Put world description here
+ - title: '!'
+ emoji: 🚀
+ description: Put ! description here
+---
+
+{{{ name }}}
diff --git a/suites/boilerplate/templates/vue/package.json.tpl b/suites/boilerplate/templates/vue/package.json.tpl
new file mode 100644
index 0000000000..633824b69a
--- /dev/null
+++ b/suites/boilerplate/templates/vue/package.json.tpl
@@ -0,0 +1,103 @@
+{
+ "name": "{{{ name }}}",
+ "version": "0.0.1",
+ "description": "{{{ description }}}",
+ "scripts": {
+ "build": "vite build && vue-tsc --project ./tsconfig.build.json",
+ "build:watch": "vite build --watch",
+ "dev": "dumi dev",
+ "docs:build": "dumi build",
+ "docs:preview": "dumi preview",
+ "lint": "npm run lint:es && npm run lint:css",
+ "lint:css": "stylelint \"{src,test}/**/*.{css,less}\"",
+ "lint:es": "eslint \"{src,test}/**/*.{js,jsx,ts,tsx,vue}\"",
+ "prepare": "husky install && dumi setup",
+ "prepublishOnly": "npm run test && npm run build",
+ "start": "npm run dev",
+ "test": "vitest",
+ "test:cov": "vitest --coverage",
+ "typecheck": "vue-tsc --noEmit"
+ },
+ "authors": [{{#author}}
+ "{{{ author }}}"
+ {{/author}}],
+ "repository": {
+ "type": "git"
+ },
+ "license": "MIT",
+ "exports": {
+ ".": {
+ "types": "./dist/typings/index.d.ts",
+ "import": "./dist/index.mjs",
+ "require": "./dist/index.umd.js"
+ },
+ "./dist/style.css": "./dist/style.css"
+ },
+ "main": "./dist/index.umd.js",
+ "module": "./dist/index.mjs",
+ "types": "./dist/typings/index.d.ts",
+ "files": [
+ "dist"
+ ],
+ "commitlint": {
+ "extends": [
+ "@commitlint/config-conventional"
+ ]
+ },
+ "lint-staged": {
+ "*.{md,json}": [
+ "prettier --write --no-error-on-unmatched-pattern"
+ ],
+ "*.{css,less}": [
+ "stylelint --fix",
+ "prettier --write"
+ ],
+ "*.{js,jsx}": [
+ "eslint --fix",
+ "prettier --write"
+ ],
+ "*.{ts,tsx}": [
+ "eslint --fix",
+ "prettier --parser=typescript --write"
+ ]
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "peerDependencies": {
+ "vue": ">=3.3.0"
+ },
+ "devDependencies": {
+ "@commitlint/cli": "^17.1.2",
+ "@commitlint/config-conventional": "^17.1.0",
+ "@dumijs/preset-vue": "^2.4.12",
+ "@eslint/js": "^9.11.1",
+ "@types/react": "^18.0.0",
+ "@types/react-dom": "^18.0.0",
+ "@typescript-eslint/eslint-plugin": "^8.7.0",
+ "@typescript-eslint/parser": "^8.7.0",
+ "@umijs/lint": "^4.3.24",
+ "@vitejs/plugin-vue": "^5.1.4",
+ "@vitejs/plugin-vue-jsx": "^4.0.1",
+ "@vitest/coverage-v8": "^2.1.1",
+ "@vue/test-utils": "^2.4.6",
+ "dumi": "{{{ version }}}",
+ "eslint": "^8.57.1",
+ "eslint-plugin-vue": "^9.17.0",
+ "happy-dom": "^15.7.4",
+ "husky": "^8.0.1",
+ "less": "^4.2.0",
+ "lint-staged": "^13.0.3",
+ "prettier": "^2.7.1",
+ "prettier-plugin-organize-imports": "^3.0.0",
+ "prettier-plugin-packagejson": "^2.2.18",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "stylelint": "^14.9.1",
+ "typescript": "~5.5.4",
+ "vite": "^5.4.8",
+ "vitest": "^2.1.1",
+ "vue": "^3.5.10",
+ "vue-tsc": "^2.1.6"
+ }
+}
diff --git a/suites/boilerplate/templates/vue/src/Bar/Bar.test.ts.tpl b/suites/boilerplate/templates/vue/src/Bar/Bar.test.ts.tpl
new file mode 100644
index 0000000000..b6d2741b9b
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Bar/Bar.test.ts.tpl
@@ -0,0 +1,15 @@
+import { mount, type VueWrapper } from '@vue/test-utils';
+import { beforeEach, describe, expect, it } from 'vitest';
+import Bar from './RootBar.vue';
+
+describe('Bar', () => {
+ let wrapper: VueWrapper>;
+
+ beforeEach(() => {
+ wrapper = mount(Bar, { props: { icon: 'V' } });
+ });
+
+ it('should render', () => {
+ expect(wrapper.html()).contain('V');
+ });
+});
diff --git a/suites/boilerplate/templates/vue/src/Bar/RootBar.vue b/suites/boilerplate/templates/vue/src/Bar/RootBar.vue
new file mode 100644
index 0000000000..18d8472d21
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Bar/RootBar.vue
@@ -0,0 +1,51 @@
+
+
+
+ {{ icon }}
+
+
+
+
+
+
+
+
+
diff --git a/suites/boilerplate/templates/vue/src/Bar/index.md.tpl b/suites/boilerplate/templates/vue/src/Bar/index.md.tpl
new file mode 100644
index 0000000000..84de568e55
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Bar/index.md.tpl
@@ -0,0 +1,39 @@
+# Bar
+
+This is an example component of Vue SFC.
+
+```vue
+
+
+
+
+ Hello Vue!
+
+
+
+
+```
+## Bar API
+
+### Props
+
+
+
+### Slots
+
+
+
+### Events
+
+
diff --git a/suites/boilerplate/templates/vue/src/Bar/index.ts b/suites/boilerplate/templates/vue/src/Bar/index.ts
new file mode 100644
index 0000000000..e6dfbcd077
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Bar/index.ts
@@ -0,0 +1 @@
+export { default as Bar } from './RootBar.vue';
diff --git a/suites/boilerplate/templates/vue/src/Foo/Foo.less b/suites/boilerplate/templates/vue/src/Foo/Foo.less
new file mode 100644
index 0000000000..a15c877ac0
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Foo/Foo.less
@@ -0,0 +1,3 @@
+.foo {
+ color: red;
+}
diff --git a/suites/boilerplate/templates/vue/src/Foo/Foo.test.ts.tpl b/suites/boilerplate/templates/vue/src/Foo/Foo.test.ts.tpl
new file mode 100644
index 0000000000..5845a912f8
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Foo/Foo.test.ts.tpl
@@ -0,0 +1,10 @@
+import { mount } from '@vue/test-utils';
+import { describe, expect, it } from 'vitest';
+import { Foo } from './index';
+
+describe('Foo', () => {
+ it('should render', () => {
+ const wrapper = mount(Foo, { props: { title: 'foo' } });
+ expect(wrapper.html()).contain('foo');
+ });
+});
diff --git a/suites/boilerplate/templates/vue/src/Foo/index.md.tpl b/suites/boilerplate/templates/vue/src/Foo/index.md.tpl
new file mode 100644
index 0000000000..6e14197c44
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Foo/index.md.tpl
@@ -0,0 +1,14 @@
+# Foo
+
+This is an example component of Vue JSX.
+
+```jsx
+import { Foo } from '{{{ name }}}';
+
+export default () =>
+```
+## Foo API
+
+### Props
+
+
diff --git a/suites/boilerplate/templates/vue/src/Foo/index.tsx b/suites/boilerplate/templates/vue/src/Foo/index.tsx
new file mode 100644
index 0000000000..fe50e1f0a3
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/Foo/index.tsx
@@ -0,0 +1,17 @@
+import { defineComponent } from 'vue';
+import './Foo.less';
+
+export const Foo = defineComponent({
+ props: {
+ /**
+ * @description 标题
+ */
+ title: {
+ type: String,
+ default: '',
+ },
+ },
+ setup({ title }) {
+ return () => {title}
;
+ },
+});
diff --git a/suites/boilerplate/templates/vue/src/index.ts b/suites/boilerplate/templates/vue/src/index.ts
new file mode 100644
index 0000000000..ac2f1b4577
--- /dev/null
+++ b/suites/boilerplate/templates/vue/src/index.ts
@@ -0,0 +1,2 @@
+export * from './Bar';
+export * from './Foo';
diff --git a/suites/boilerplate/templates/vue/tsconfig.build.json.tpl b/suites/boilerplate/templates/vue/tsconfig.build.json.tpl
new file mode 100644
index 0000000000..293da39e07
--- /dev/null
+++ b/suites/boilerplate/templates/vue/tsconfig.build.json.tpl
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "emitDeclarationOnly": true,
+ "declarationDir": "./dist/typings",
+ "lib": ["esnext", "dom"]
+ },
+ "include": ["src/**/*"],
+ "exclude": ["src/**/*.test.*"]
+}
diff --git a/suites/boilerplate/templates/vue/tsconfig.json.tpl b/suites/boilerplate/templates/vue/tsconfig.json.tpl
new file mode 100644
index 0000000000..45ebc86437
--- /dev/null
+++ b/suites/boilerplate/templates/vue/tsconfig.json.tpl
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "declaration": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "strictNullChecks": false,
+ "baseUrl": "./",
+ "paths": {
+ "@@/*": [".dumi/tmp/*"],
+ "{{{ name }}}": ["src"],
+ "{{{ name }}}/*": ["src/*", "*"]
+ }
+ },
+ "include": [".dumirc.ts", "src/**/*"]
+}
diff --git a/suites/boilerplate/templates/vue/vite.config.mts b/suites/boilerplate/templates/vue/vite.config.mts
new file mode 100644
index 0000000000..bbb0d4338c
--- /dev/null
+++ b/suites/boilerplate/templates/vue/vite.config.mts
@@ -0,0 +1,36 @@
+import { defineConfig } from 'vite';
+import { resolve } from 'node:path';
+import vue from '@vitejs/plugin-vue';
+import vueJsx from '@vitejs/plugin-vue-jsx';
+
+
+const externals = ['vue'];
+
+export default defineConfig({
+ plugins: [
+ vue(),
+ vueJsx(),
+ ],
+ build: {
+ lib: {
+ entry: resolve(__dirname, 'src/index.ts'),
+ name: 'index',
+ fileName: 'index',
+ },
+ rollupOptions: {
+ external: [...externals],
+ output: {
+ globals: {
+ 'vue': 'Vue',
+ },
+ },
+ },
+ outDir: 'dist',
+ },
+ resolve: {
+ dedupe: ['vue'],
+ },
+ optimizeDeps: {
+ include: [...externals],
+ },
+});
diff --git a/suites/boilerplate/templates/vue/vitest.config.mts b/suites/boilerplate/templates/vue/vitest.config.mts
new file mode 100644
index 0000000000..45c99b72f4
--- /dev/null
+++ b/suites/boilerplate/templates/vue/vitest.config.mts
@@ -0,0 +1,19 @@
+import { defineConfig } from 'vitest/config';
+import vue from '@vitejs/plugin-vue';
+import vueJsx from '@vitejs/plugin-vue-jsx';
+
+
+export default defineConfig({
+ plugins: [
+ vue(),
+ vueJsx(),
+ ],
+ test: {
+ environment: 'happy-dom',
+ include: ['./**/*.test.{ts,js,tsx}'],
+ coverage: {
+ provider: 'v8',
+ reporter: ['html', 'text', 'json'],
+ },
+ },
+});