├── src ├── composables │ ├── index.ts │ └── dark.ts ├── pages │ ├── [...all].vue │ ├── README.md │ ├── hi │ │ └── [name].vue │ └── index.vue ├── App.vue ├── styles │ └── main.css ├── components │ ├── TheCounter.vue │ ├── TheInput.vue │ ├── TheFooter.vue │ └── README.md └── main.ts ├── .github ├── FUNDING.yml └── workflows │ └── test.yml ├── .npmrc ├── .gitignore ├── test ├── basic.test.ts ├── __snapshots__ │ └── component.test.ts.snap └── component.test.ts ├── eslint.config.js ├── shims.d.ts ├── .editorconfig ├── netlify.toml ├── .vscode ├── extensions.json └── settings.json ├── public └── favicon.svg ├── components.d.ts ├── tsconfig.json ├── uno.config.ts ├── typed-router.d.ts ├── pnpm-workspace.yaml ├── index.html ├── LICENSE ├── package.json ├── vite.config.ts ├── README.zh-CN.md ├── README.md └── auto-imports.d.ts /src/composables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dark' 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: antfu 2 | github: [antfu] 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /src/pages/[...all].vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/composables/dark.ts: -------------------------------------------------------------------------------- 1 | export const isDark = useDark() 2 | export const toggleDark = useToggle(isDark) 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vite-ssg-dist 3 | .vite-ssg-temp 4 | *.local 5 | dist 6 | dist-ssr 7 | node_modules 8 | .idea/ 9 | *.log 10 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/styles/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #app { 4 | height: 100%; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | html.dark { 10 | color-scheme: dark; 11 | } 12 | -------------------------------------------------------------------------------- /test/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest' 2 | 3 | describe('hi', () => { 4 | it('should works', () => { 5 | expect(1 + 1).toEqual(2) 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import antfu from '@antfu/eslint-config' 2 | 3 | export default antfu( 4 | { 5 | unocss: true, 6 | formatters: true, 7 | pnpm: true, 8 | }, 9 | ) 10 | -------------------------------------------------------------------------------- /shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | 4 | const component: DefineComponent 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "dist" 3 | command = "pnpm run build" 4 | 5 | [build.environment] 6 | NODE_VERSION = "23" 7 | 8 | [[redirects]] 9 | from = "/*" 10 | to = "/index.html" 11 | status = 200 12 | -------------------------------------------------------------------------------- /test/__snapshots__/component.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`component of TheCounter.vue > should render 1`] = `"
10
"`; 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "antfu.vite", 4 | "antfu.iconify", 5 | "antfu.unocss", 6 | "antfu.goto-alias", 7 | "vue.volar", 8 | "dbaeumer.vscode-eslint", 9 | "EditorConfig.EditorConfig" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/TheCounter.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | -------------------------------------------------------------------------------- /src/components/TheInput.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | -------------------------------------------------------------------------------- /src/components/TheFooter.vue: -------------------------------------------------------------------------------- 1 | 16 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createRouter, createWebHistory } from 'vue-router' 3 | import { routes } from 'vue-router/auto-routes' 4 | import App from './App.vue' 5 | 6 | import './styles/main.css' 7 | import 'uno.css' 8 | 9 | const app = createApp(App) 10 | const router = createRouter({ 11 | routes, 12 | history: createWebHistory(import.meta.env.BASE_URL), 13 | }) 14 | app.use(router) 15 | app.mount('#app') 16 | -------------------------------------------------------------------------------- /src/components/README.md: -------------------------------------------------------------------------------- 1 | ## Components 2 | 3 | Components in this dir will be auto-registered and on-demand, powered by [`unplugin-vue-components`](https://github.com/antfu/unplugin-vue-components). 4 | 5 | ### Icons 6 | 7 | You can use icons from almost any icon sets by the power of [Iconify](https://iconify.design/). 8 | 9 | It will only bundle the icons you use. Check out [`unplugin-icons`](https://github.com/antfu/unplugin-icons) for more details. 10 | -------------------------------------------------------------------------------- /src/pages/README.md: -------------------------------------------------------------------------------- 1 | ## File-based Routing 2 | 3 | Routes will be auto-generated for Vue files in this dir with the same file structure. 4 | Check out [`unplugin-vue-router`](https://github.com/posva/unplugin-vue-router) for more details. 5 | 6 | ### Path Aliasing 7 | 8 | `~/` is aliased to `./src/` folder. 9 | 10 | For example, instead of having 11 | 12 | ```ts 13 | import { isDark } from '../../../../composables' 14 | ``` 15 | 16 | now, you can use 17 | 18 | ```ts 19 | import { isDark } from '~/composables' 20 | ``` 21 | -------------------------------------------------------------------------------- /src/pages/hi/[name].vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 23 | -------------------------------------------------------------------------------- /components.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | // @ts-nocheck 3 | // Generated by unplugin-vue-components 4 | // Read more: https://github.com/vuejs/core/pull/3399 5 | // biome-ignore lint: disable 6 | export {} 7 | 8 | /* prettier-ignore */ 9 | declare module 'vue' { 10 | export interface GlobalComponents { 11 | RouterLink: typeof import('vue-router')['RouterLink'] 12 | RouterView: typeof import('vue-router')['RouterView'] 13 | TheCounter: typeof import('./src/components/TheCounter.vue')['default'] 14 | TheFooter: typeof import('./src/components/TheFooter.vue')['default'] 15 | TheInput: typeof import('./src/components/TheInput.vue')['default'] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/component.test.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import { describe, expect, it } from 'vitest' 3 | import TheCounter from '../src/components/TheCounter.vue' 4 | 5 | describe('component of TheCounter.vue', () => { 6 | it('should render', () => { 7 | const wrapper = mount(TheCounter, { props: { initial: 10 } }) 8 | expect(wrapper.text()).toContain('10') 9 | expect(wrapper.html()).toMatchSnapshot() 10 | }) 11 | 12 | it('should be interactive', async () => { 13 | const wrapper = mount(TheCounter, { props: { initial: 0 } }) 14 | expect(wrapper.text()).toContain('0') 15 | 16 | expect(wrapper.find('.inc').exists()).toBe(true) 17 | 18 | await wrapper.get('button').trigger('click') 19 | 20 | expect(wrapper.text()).toContain('1') 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "jsx": "preserve", 5 | "lib": ["DOM", "ESNext"], 6 | "baseUrl": ".", 7 | "module": "ESNext", 8 | "moduleResolution": "bundler", 9 | "paths": { 10 | "~/*": ["src/*"] 11 | }, 12 | "resolveJsonModule": true, 13 | "types": [ 14 | "vite/client", 15 | "unplugin-vue-macros/macros-global", 16 | "unplugin-vue-router/client" 17 | ], 18 | "allowJs": true, 19 | "strict": true, 20 | "strictNullChecks": true, 21 | "noUnusedLocals": true, 22 | "noEmit": true, 23 | "esModuleInterop": true, 24 | "forceConsistentCasingInFileNames": true, 25 | "skipLibCheck": true 26 | }, 27 | "exclude": [ 28 | "dist", 29 | "node_modules", 30 | "eslint.config.js" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /uno.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineConfig, 3 | presetAttributify, 4 | presetIcons, 5 | presetWebFonts, 6 | presetWind4, 7 | } from 'unocss' 8 | 9 | export default defineConfig({ 10 | shortcuts: [ 11 | ['btn', 'px-4 py-1 rounded inline-block bg-teal-600 text-white cursor-pointer hover:bg-teal-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'], 12 | ['icon-btn', 'text-[0.9em] inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600'], 13 | ], 14 | presets: [ 15 | presetWind4(), 16 | presetAttributify(), 17 | presetIcons({ 18 | scale: 1.2, 19 | warn: true, 20 | }), 21 | presetWebFonts({ 22 | fonts: { 23 | sans: 'DM Sans', 24 | serif: 'DM Serif Display', 25 | mono: 'DM Mono', 26 | }, 27 | }), 28 | ], 29 | }) 30 | -------------------------------------------------------------------------------- /typed-router.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /* prettier-ignore */ 3 | // @ts-nocheck 4 | // Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️ 5 | // It's recommended to commit this file. 6 | // Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry. 7 | 8 | declare module 'vue-router/auto-routes' { 9 | import type { 10 | RouteRecordInfo, 11 | ParamValue, 12 | ParamValueOneOrMore, 13 | ParamValueZeroOrMore, 14 | ParamValueZeroOrOne, 15 | } from 'vue-router' 16 | 17 | /** 18 | * Route name map generated by unplugin-vue-router 19 | */ 20 | export interface RouteNamedMap { 21 | '/': RouteRecordInfo<'/', '/', Record, Record>, 22 | '/[...all]': RouteRecordInfo<'/[...all]', '/:all(.*)', { all: ParamValue }, { all: ParamValue }>, 23 | '/hi/[name]': RouteRecordInfo<'/hi/[name]', '/hi/:name', { name: ParamValue }, { name: ParamValue }>, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: [] 2 | catalogs: 3 | build: 4 | '@iconify-json/carbon': ^1.2.9 5 | '@vitejs/plugin-vue': ^5.2.4 6 | jsdom: ^26.1.0 7 | unocss: ^66.2.0 8 | unplugin: ^2.3.5 9 | unplugin-auto-import: ^19.3.0 10 | unplugin-vue-components: ^28.7.0 11 | unplugin-vue-macros: ^2.14.5 12 | unplugin-vue-router: ^0.12.0 13 | vite: ^6.3.5 14 | dev: 15 | '@antfu/eslint-config': ^4.14.1 16 | '@types/node': ^22.15.31 17 | '@unocss/eslint-plugin': ^66.2.0 18 | '@vue-macros/volar': ^3.0.0-beta.14 19 | '@vue/test-utils': ^2.4.6 20 | eslint: ^9.28.0 21 | eslint-plugin-format: ^1.0.1 22 | lint-staged: ^16.1.0 23 | simple-git-hooks: ^2.13.0 24 | taze: ^19.1.0 25 | typescript: ^5.8.3 26 | vitest: ^3.2.3 27 | vue-tsc: ^2.2.10 28 | frontend: 29 | '@vueuse/core': ^13.3.0 30 | vue: ^3.5.16 31 | vue-router: ^4.5.1 32 | onlyBuiltDependencies: 33 | - esbuild 34 | - simple-git-hooks 35 | - unrs-resolver 36 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | 16 | timeout-minutes: 10 17 | 18 | strategy: 19 | matrix: 20 | node_version: [lts/*] 21 | os: [ubuntu-latest, windows-latest] 22 | fail-fast: false 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: pnpm/action-setup@v4 27 | 28 | - name: Set node version to ${{ matrix.node_version }} 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: ${{ matrix.node_version }} 32 | cache: pnpm 33 | 34 | - name: Install 35 | run: pnpm i 36 | 37 | - name: Build 38 | run: pnpm run build 39 | 40 | - name: Test 41 | run: pnpm run test 42 | 43 | - name: Lint 44 | run: pnpm run lint 45 | 46 | - name: TypeCheck 47 | run: pnpm run typecheck 48 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vitesse Lite 8 | 9 | 10 | 11 |
12 | 15 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/pages/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-PRESENT Anthony Fu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.css": "postcss" 4 | }, 5 | 6 | // Enable the ESlint flat config support 7 | "eslint.experimental.useFlatConfig": true, 8 | 9 | // Disable the default formatter 10 | "prettier.enable": false, 11 | "editor.formatOnSave": false, 12 | 13 | // Auto fix 14 | "editor.codeActionsOnSave": { 15 | "source.fixAll.eslint": "explicit", 16 | "source.organizeImports": "never" 17 | }, 18 | 19 | // Silent the stylistic rules in you IDE, but still auto fix them 20 | "eslint.rules.customizations": [ 21 | { "rule": "style/*", "severity": "off" }, 22 | { "rule": "*-indent", "severity": "off" }, 23 | { "rule": "*-spacing", "severity": "off" }, 24 | { "rule": "*-spaces", "severity": "off" }, 25 | { "rule": "*-order", "severity": "off" }, 26 | { "rule": "*-dangle", "severity": "off" }, 27 | { "rule": "*-newline", "severity": "off" }, 28 | { "rule": "*quotes", "severity": "off" }, 29 | { "rule": "*semi", "severity": "off" } 30 | ], 31 | 32 | // The following is optional. 33 | // It's better to put under project setting `.vscode/settings.json` 34 | // to avoid conflicts with working with different eslint configs 35 | // that does not support all formats. 36 | "eslint.validate": [ 37 | "javascript", 38 | "javascriptreact", 39 | "typescript", 40 | "typescriptreact", 41 | "vue", 42 | "html", 43 | "markdown", 44 | "json", 45 | "jsonc", 46 | "yaml" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "private": true, 4 | "packageManager": "pnpm@10.12.1", 5 | "scripts": { 6 | "build": "vite build", 7 | "dev": "vite --port 3333 --open", 8 | "lint": "eslint .", 9 | "typecheck": "vue-tsc", 10 | "preview": "vite preview", 11 | "test": "vitest", 12 | "up": "taze major -I", 13 | "postinstall": "npx simple-git-hooks" 14 | }, 15 | "dependencies": { 16 | "@vueuse/core": "catalog:frontend", 17 | "vue": "catalog:frontend", 18 | "vue-router": "catalog:frontend" 19 | }, 20 | "devDependencies": { 21 | "@antfu/eslint-config": "catalog:dev", 22 | "@iconify-json/carbon": "catalog:build", 23 | "@types/node": "catalog:dev", 24 | "@unocss/eslint-plugin": "catalog:dev", 25 | "@vitejs/plugin-vue": "catalog:build", 26 | "@vue-macros/volar": "catalog:dev", 27 | "@vue/test-utils": "catalog:dev", 28 | "eslint": "catalog:dev", 29 | "eslint-plugin-format": "catalog:dev", 30 | "jsdom": "catalog:build", 31 | "lint-staged": "catalog:dev", 32 | "simple-git-hooks": "catalog:dev", 33 | "taze": "catalog:dev", 34 | "typescript": "catalog:dev", 35 | "unocss": "catalog:build", 36 | "unplugin-auto-import": "catalog:build", 37 | "unplugin-vue-components": "catalog:build", 38 | "unplugin-vue-macros": "catalog:build", 39 | "unplugin-vue-router": "catalog:build", 40 | "vite": "catalog:build", 41 | "vitest": "catalog:dev", 42 | "vue-tsc": "catalog:dev" 43 | }, 44 | "resolutions": { 45 | "unplugin": "catalog:build", 46 | "vite": "catalog:build" 47 | }, 48 | "simple-git-hooks": { 49 | "pre-commit": "pnpm lint-staged" 50 | }, 51 | "lint-staged": { 52 | "*": "eslint --fix" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import path from 'node:path' 4 | import Vue from '@vitejs/plugin-vue' 5 | import UnoCSS from 'unocss/vite' 6 | import AutoImport from 'unplugin-auto-import/vite' 7 | import Components from 'unplugin-vue-components/vite' 8 | import VueMacros from 'unplugin-vue-macros/vite' 9 | import { VueRouterAutoImports } from 'unplugin-vue-router' 10 | import VueRouter from 'unplugin-vue-router/vite' 11 | import { defineConfig } from 'vite' 12 | 13 | export default defineConfig({ 14 | resolve: { 15 | alias: { 16 | '~/': `${path.resolve(__dirname, 'src')}/`, 17 | }, 18 | }, 19 | plugins: [ 20 | // https://github.com/posva/unplugin-vue-router 21 | VueRouter(), 22 | 23 | VueMacros({ 24 | defineOptions: false, 25 | defineModels: false, 26 | plugins: { 27 | vue: Vue({ 28 | script: { 29 | propsDestructure: true, 30 | defineModel: true, 31 | }, 32 | }), 33 | }, 34 | }), 35 | 36 | // https://github.com/antfu/unplugin-auto-import 37 | AutoImport({ 38 | imports: [ 39 | 'vue', 40 | '@vueuse/core', 41 | VueRouterAutoImports, 42 | { 43 | // add any other imports you were relying on 44 | 'vue-router/auto': ['useLink'], 45 | }, 46 | ], 47 | dts: true, 48 | dirs: [ 49 | './src/composables', 50 | ], 51 | vueTemplate: true, 52 | }), 53 | 54 | // https://github.com/antfu/vite-plugin-components 55 | Components({ 56 | dts: true, 57 | }), 58 | 59 | // https://github.com/antfu/unocss 60 | // see uno.config.ts for config 61 | UnoCSS(), 62 | ], 63 | 64 | // https://github.com/vitest-dev/vitest 65 | test: { 66 | environment: 'jsdom', 67 | }, 68 | }) 69 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 |

2 | Vitesse - Opinionated Vite Starter Template 3 |

4 | 5 |
6 | 在线 Demo 7 |
8 | 9 |
10 | 轻量版的 Vitesse 11 |
12 | 13 |
14 | 15 |

16 | English | 简体中文 17 |

18 | 19 |
20 | 21 | ## 特性 22 | 23 | - ⚡️ [Vue 3](https://github.com/vuejs/core), [Vite](https://github.com/vitejs/vite), [pnpm](https://pnpm.io/), [ESBuild](https://github.com/evanw/esbuild) - 就是快! 24 | 25 | - 🗂 [基于文件的路由](./src/pages) 26 | 27 | - 📦 [组件自动化加载](./src/components) 28 | 29 | - 🎨 [UnoCSS](https://github.com/unocss/unocss) - 高性能且极具灵活性的即时原子化 CSS 引擎 30 | 31 | - 😃 [各种图标集为你所用](https://github.com/antfu/unocss/tree/main/packages/preset-icons) 32 | 33 | - 🔥 使用 [新的 `