diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index a843dc4..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -test/fixtures diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index e43ef3f..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - root: true, - env: { - node: true - }, - extends: [ - 'plugin:vue/essential', - 'eslint:recommended', - require.resolve('./recommended') - ], - - overrides: [{ - files: ['test/**.spec.js'], - env: { - jest: true - }, - rules: { - '@typescript-eslint/no-var-requires': 'off' - } - }] -} diff --git a/.github/MAINTENANCE.md b/.github/MAINTENANCE.md new file mode 100644 index 0000000..4ca916d --- /dev/null +++ b/.github/MAINTENANCE.md @@ -0,0 +1,10 @@ +This document explains how to perform the project's maintenance tasks. + +### Creating a new release + +Anyone with write access to the repository can request a new release. To do so, follow these steps: + +1. Run `pnpm version ` locally to bump the version number and create a new commit / tag. +2. Push the commit and tag to the repository by running `git push --follow-tags`. +3. The release will be automatically published to npm by GitHub Actions once approved by an administrator. +4. Go to and create a new release with the tag that was just created. Describe the notable changes in the release notes. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1663a05..178878f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,7 @@ on: push: branches: - '**' + - '!renovate/**' paths-ignore: - README.md pull_request: @@ -20,6 +21,8 @@ jobs: - windows-latest node-version: - 20 + env: + CYPRESS_INSTALL_BINARY: 0 name: Node ${{ matrix.node-version }} on ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -27,7 +30,7 @@ jobs: submodules: 'recursive' - uses: pnpm/action-setup@v3 with: - version: 8 + version: 9 - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..b729f93 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,28 @@ +name: Publish + +on: + push: + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +jobs: + release: + # Use Publish environment for deployment protection + environment: Publish + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + registry-url: 'https://registry.npmjs.org' + - run: pnpm install + - run: pnpm publish --no-git-checks + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index d5f19d8..87807d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules package-lock.json +dist diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..759232e --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid" +} diff --git a/README.md b/README.md index c4ab58c..1da1806 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,152 @@ # @vue/eslint-config-typescript -> eslint-config-typescript for Vue +ESLint configuration for Vue 3 + TypeScript projects. See [@typescript-eslint/eslint-plugin](https://typescript-eslint.io/rules/) for available rules. -This config is specifically designed to be used by `@vue/cli` & `create-vue` setups +This config is specifically designed to be used by `create-vue` setups and is not meant for outside use (it can be used but some adaptations on the user side might be needed - for details see the config file). A part of its design is that this config may implicitly depend on -other parts of `@vue/cli`/`create-vue` setups, such as `eslint-plugin-vue` being +other parts of `create-vue` setups, such as `eslint-plugin-vue` being extended in the same resulting config. -## Installation +> [!NOTE] +> The current version doesn't support the legacy `.eslintrc*` configuration format. For that you need to use version 13 or earlier. See the [corresponding README](https://www.npmjs.com/package/@vue/eslint-config-typescript/v/legacy-eslintrc) for more usage instructions. -In order to work around [a known limitation in ESLint](https://github.com/eslint/eslint/issues/3458), we recommend you to use this package alongside `@rushstack/eslint-patch`, so that you don't have to install too many dependencies: +## Installation ```sh -npm add --dev @vue/eslint-config-typescript @rushstack/eslint-patch +npm add --dev @vue/eslint-config-typescript ``` -## Usage +Please also make sure that you have `typescript` and `eslint` installed. -This package comes with 2 rulesets. +## Usage -### `@vue/eslint-config-typescript` +Because of the complexity of the configurations, this package exports several utilities: -This ruleset is the base configuration for Vue-TypeScript projects. -Besides setting the parser and plugin options, it also turns off several conflicting rules in the `eslint:recommended` ruleset. -So when used alongside other sharable configs, this config should be placed at the end of the `extends` array. +- `defineConfigWithVueTs`, a utility function whose type signature is the same as the [`config` function from `typescript-eslint`](https://typescript-eslint.io/packages/typescript-eslint#config), but will modify the given ESLint config to work with Vue.js + TypeScript. +- `vueTsConfigs`, contains all the [shared configurations from `typescript-eslint`](https://typescript-eslint.io/users/configs) (in camelCase, e.g. `vueTsConfigs.recommendedTypeChecked`), and applies to `.vue` files in addition to TypeScript files. +- a Vue-specific config factory: `configureVueProject({ scriptLangs, rootDir })`. More info below. -An example `.eslintrc.cjs`: +### Minimal Setup ```js -/* eslint-env node */ -require("@rushstack/eslint-patch/modern-module-resolution") - -module.exports = { - extends: [ - 'eslint:recommended', - 'plugin:vue/vue3-essential', - '@vue/eslint-config-typescript' - ] -} +// eslint.config.mjs +import pluginVue from 'eslint-plugin-vue' +import { + defineConfigWithVueTs, + vueTsConfigs, +} from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) ``` -### `@vue/eslint-config-typescript/recommended` +The above configuration enables [the essential rules for Vue 3](https://eslint.vuejs.org/rules/#priority-a-essential-error-prevention) and [the recommended rules for TypeScript](https://typescript-eslint.io/rules/?=recommended). -This is extended from the `@typescript-eslint/recommended` ruleset, which is an **_opinionated_** ruleset. -See the [original documentation](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/src/configs#recommended) for more information. +All the ` + + diff --git a/examples/allow-js/package.json b/examples/allow-js/package.json new file mode 100644 index 0000000..674beac --- /dev/null +++ b/examples/allow-js/package.json @@ -0,0 +1,30 @@ +{ + "name": "allow-js", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/allow-js/public/favicon.ico b/examples/allow-js/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/allow-js/public/favicon.ico differ diff --git a/examples/allow-js/src/App.vue b/examples/allow-js/src/App.vue new file mode 100644 index 0000000..a361240 --- /dev/null +++ b/examples/allow-js/src/App.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/examples/allow-js/src/assets/base.css b/examples/allow-js/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/allow-js/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/allow-js/src/assets/logo.svg b/examples/allow-js/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/allow-js/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/allow-js/src/assets/main.css b/examples/allow-js/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/allow-js/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/allow-js/src/components/HelloWorld.vue b/examples/allow-js/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/allow-js/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/allow-js/src/components/TheWelcome.vue b/examples/allow-js/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/allow-js/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/allow-js/src/components/WelcomeItem.vue b/examples/allow-js/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/allow-js/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/allow-js/src/components/icons/IconCommunity.vue b/examples/allow-js/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/allow-js/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/allow-js/src/components/icons/IconDocumentation.vue b/examples/allow-js/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/allow-js/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/allow-js/src/components/icons/IconEcosystem.vue b/examples/allow-js/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/allow-js/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/allow-js/src/components/icons/IconSupport.vue b/examples/allow-js/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/allow-js/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/allow-js/src/components/icons/IconTooling.vue b/examples/allow-js/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/allow-js/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/allow-js/src/foo.js b/examples/allow-js/src/foo.js new file mode 100644 index 0000000..c2f6126 --- /dev/null +++ b/examples/allow-js/src/foo.js @@ -0,0 +1,3 @@ +export default function foo() { + console.log('this is a plain js file') +} diff --git a/examples/allow-js/src/main.ts b/examples/allow-js/src/main.ts new file mode 100644 index 0000000..06b99b2 --- /dev/null +++ b/examples/allow-js/src/main.ts @@ -0,0 +1,10 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +import foo from './foo' + +createApp(App).mount('#app') + +foo() diff --git a/examples/allow-js/tsconfig.app.json b/examples/allow-js/tsconfig.app.json new file mode 100644 index 0000000..97926e7 --- /dev/null +++ b/examples/allow-js/tsconfig.app.json @@ -0,0 +1,17 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + + "allowJs": true, + "checkJs": true + } +} diff --git a/examples/allow-js/tsconfig.json b/examples/allow-js/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/allow-js/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/allow-js/tsconfig.node.json b/examples/allow-js/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/allow-js/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/allow-js/vite.config.ts b/examples/allow-js/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/allow-js/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/api-before-14.3/.editorconfig b/examples/api-before-14.3/.editorconfig new file mode 100644 index 0000000..ecea360 --- /dev/null +++ b/examples/api-before-14.3/.editorconfig @@ -0,0 +1,6 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/examples/api-before-14.3/.gitignore b/examples/api-before-14.3/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/api-before-14.3/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/api-before-14.3/.prettierrc.json b/examples/api-before-14.3/.prettierrc.json new file mode 100644 index 0000000..effc164 --- /dev/null +++ b/examples/api-before-14.3/.prettierrc.json @@ -0,0 +1,7 @@ + +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "singleQuote": true, + "arrowParens": "avoid" +} diff --git a/examples/api-before-14.3/.vscode/extensions.json b/examples/api-before-14.3/.vscode/extensions.json new file mode 100644 index 0000000..de51a0a --- /dev/null +++ b/examples/api-before-14.3/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "Vue.volar", + "vitest.explorer", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/examples/api-before-14.3/README.md b/examples/api-before-14.3/README.md new file mode 100644 index 0000000..9bb47f8 --- /dev/null +++ b/examples/api-before-14.3/README.md @@ -0,0 +1,61 @@ +# api-before-14.3 + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run Unit Tests with [Vitest](https://vitest.dev/) + +```sh +npm run test:unit +``` + +### Run End-to-End Tests with [Cypress](https://www.cypress.io/) + +```sh +npm run test:e2e:dev +``` + +This runs the end-to-end tests against the Vite development server. +It is much faster than the production build. + +But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments): + +```sh +npm run build +npm run test:e2e +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/api-before-14.3/cypress.config.ts b/examples/api-before-14.3/cypress.config.ts new file mode 100644 index 0000000..0f66080 --- /dev/null +++ b/examples/api-before-14.3/cypress.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}', + baseUrl: 'http://localhost:4173' + } +}) diff --git a/examples/api-before-14.3/cypress/e2e/example.cy.ts b/examples/api-before-14.3/cypress/e2e/example.cy.ts new file mode 100644 index 0000000..7554c35 --- /dev/null +++ b/examples/api-before-14.3/cypress/e2e/example.cy.ts @@ -0,0 +1,8 @@ +// https://on.cypress.io/api + +describe('My First Test', () => { + it('visits the app root url', () => { + cy.visit('/') + cy.contains('h1', 'You did it!') + }) +}) diff --git a/examples/api-before-14.3/cypress/fixtures/example.json b/examples/api-before-14.3/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/examples/api-before-14.3/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/examples/api-before-14.3/cypress/support/commands.ts b/examples/api-before-14.3/cypress/support/commands.ts new file mode 100644 index 0000000..9b7bb8e --- /dev/null +++ b/examples/api-before-14.3/cypress/support/commands.ts @@ -0,0 +1,39 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } + +export {} diff --git a/examples/api-before-14.3/cypress/support/e2e.ts b/examples/api-before-14.3/cypress/support/e2e.ts new file mode 100644 index 0000000..d68db96 --- /dev/null +++ b/examples/api-before-14.3/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/examples/api-before-14.3/cypress/tsconfig.json b/examples/api-before-14.3/cypress/tsconfig.json new file mode 100644 index 0000000..a13c5d6 --- /dev/null +++ b/examples/api-before-14.3/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["./e2e/**/*", "./support/**/*"], + "compilerOptions": { + "isolatedModules": false, + "types": ["cypress"] + } +} diff --git a/examples/api-before-14.3/env.d.ts b/examples/api-before-14.3/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/api-before-14.3/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/api-before-14.3/eslint.config.js b/examples/api-before-14.3/eslint.config.js new file mode 100644 index 0000000..6fe3f0a --- /dev/null +++ b/examples/api-before-14.3/eslint.config.js @@ -0,0 +1,34 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' +import pluginVitest from '@vitest/eslint-plugin' +import pluginCypress from 'eslint-plugin-cypress/flat' +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig({ extends: ['recommendedTypeChecked'] }), + + { + ...pluginVitest.configs.recommended, + files: ['src/**/__tests__/*'], + }, + + { + ...pluginCypress.configs.recommended, + files: [ + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}' + ], + }, + skipFormatting, +] diff --git a/examples/api-before-14.3/index.html b/examples/api-before-14.3/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/api-before-14.3/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/api-before-14.3/package.json b/examples/api-before-14.3/package.json new file mode 100644 index 0000000..74f8df8 --- /dev/null +++ b/examples/api-before-14.3/package.json @@ -0,0 +1,48 @@ +{ + "name": "api-before-14.3", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:unit": "vitest", + "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'", + "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix", + "format": "prettier --write src/" + }, + "dependencies": { + "pinia": "^3.0.1", + "vue": "^3.5.13", + "vue-router": "^4.5.0" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/jsdom": "^21.1.7", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vitest/eslint-plugin": "^1.1.38", + "@vue/eslint-config-prettier": "^10.2.0", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.7.0", + "cypress": "^14.2.1", + "eslint": "^9.23.0", + "eslint-plugin-cypress": "^4.2.0", + "eslint-plugin-vue": "~10.0.0", + "jsdom": "^26.0.0", + "npm-run-all2": "^7.0.2", + "prettier": "3.5.3", + "start-server-and-test": "^2.0.11", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vite-plugin-vue-devtools": "^7.7.2", + "vitest": "^3.1.1", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/api-before-14.3/public/favicon.ico b/examples/api-before-14.3/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/api-before-14.3/public/favicon.ico differ diff --git a/examples/api-before-14.3/src/App.vue b/examples/api-before-14.3/src/App.vue new file mode 100644 index 0000000..7905b05 --- /dev/null +++ b/examples/api-before-14.3/src/App.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/examples/api-before-14.3/src/assets/base.css b/examples/api-before-14.3/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/api-before-14.3/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/api-before-14.3/src/assets/logo.svg b/examples/api-before-14.3/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/api-before-14.3/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/api-before-14.3/src/assets/main.css b/examples/api-before-14.3/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/api-before-14.3/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/api-before-14.3/src/components/HelloWorld.vue b/examples/api-before-14.3/src/components/HelloWorld.vue new file mode 100644 index 0000000..d174cf8 --- /dev/null +++ b/examples/api-before-14.3/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/api-before-14.3/src/components/TheWelcome.vue b/examples/api-before-14.3/src/components/TheWelcome.vue new file mode 100644 index 0000000..e65a66b --- /dev/null +++ b/examples/api-before-14.3/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/api-before-14.3/src/components/WelcomeItem.vue b/examples/api-before-14.3/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/api-before-14.3/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/api-before-14.3/src/components/__tests__/HelloWorld.spec.ts b/examples/api-before-14.3/src/components/__tests__/HelloWorld.spec.ts new file mode 100644 index 0000000..2533202 --- /dev/null +++ b/examples/api-before-14.3/src/components/__tests__/HelloWorld.spec.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest' + +import { mount } from '@vue/test-utils' +import HelloWorld from '../HelloWorld.vue' + +describe('HelloWorld', () => { + it('renders properly', () => { + const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) + expect(wrapper.text()).toContain('Hello Vitest') + }) +}) diff --git a/examples/api-before-14.3/src/components/icons/IconCommunity.vue b/examples/api-before-14.3/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/api-before-14.3/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/api-before-14.3/src/components/icons/IconDocumentation.vue b/examples/api-before-14.3/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/api-before-14.3/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/api-before-14.3/src/components/icons/IconEcosystem.vue b/examples/api-before-14.3/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/api-before-14.3/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/api-before-14.3/src/components/icons/IconSupport.vue b/examples/api-before-14.3/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/api-before-14.3/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/api-before-14.3/src/components/icons/IconTooling.vue b/examples/api-before-14.3/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/api-before-14.3/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/api-before-14.3/src/main.ts b/examples/api-before-14.3/src/main.ts new file mode 100644 index 0000000..5dcad83 --- /dev/null +++ b/examples/api-before-14.3/src/main.ts @@ -0,0 +1,14 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) + +app.mount('#app') diff --git a/examples/api-before-14.3/src/router/index.ts b/examples/api-before-14.3/src/router/index.ts new file mode 100644 index 0000000..ce51fcf --- /dev/null +++ b/examples/api-before-14.3/src/router/index.ts @@ -0,0 +1,24 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' +import type { Component } from 'vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: async (): Promise<{ default: Component }> => import('../views/AboutView.vue') + } + ] +}) + +export default router diff --git a/examples/api-before-14.3/src/stores/counter.ts b/examples/api-before-14.3/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/examples/api-before-14.3/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/examples/api-before-14.3/src/views/AboutView.vue b/examples/api-before-14.3/src/views/AboutView.vue new file mode 100644 index 0000000..756ad2a --- /dev/null +++ b/examples/api-before-14.3/src/views/AboutView.vue @@ -0,0 +1,15 @@ + + + diff --git a/examples/api-before-14.3/src/views/HomeView.vue b/examples/api-before-14.3/src/views/HomeView.vue new file mode 100644 index 0000000..d5c0217 --- /dev/null +++ b/examples/api-before-14.3/src/views/HomeView.vue @@ -0,0 +1,9 @@ + + + diff --git a/examples/api-before-14.3/tsconfig.app.json b/examples/api-before-14.3/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/api-before-14.3/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/api-before-14.3/tsconfig.json b/examples/api-before-14.3/tsconfig.json new file mode 100644 index 0000000..5304731 --- /dev/null +++ b/examples/api-before-14.3/tsconfig.json @@ -0,0 +1,17 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ], + "compilerOptions": { + "module": "NodeNext" + } +} diff --git a/examples/api-before-14.3/tsconfig.node.json b/examples/api-before-14.3/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/api-before-14.3/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/api-before-14.3/tsconfig.vitest.json b/examples/api-before-14.3/tsconfig.vitest.json new file mode 100644 index 0000000..571995d --- /dev/null +++ b/examples/api-before-14.3/tsconfig.vitest.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.app.json", + "exclude": [], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo", + + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/examples/api-before-14.3/vite.config.ts b/examples/api-before-14.3/vite.config.ts new file mode 100644 index 0000000..c036b6f --- /dev/null +++ b/examples/api-before-14.3/vite.config.ts @@ -0,0 +1,20 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/api-before-14.3/vitest.config.ts b/examples/api-before-14.3/vitest.config.ts new file mode 100644 index 0000000..4b1c897 --- /dev/null +++ b/examples/api-before-14.3/vitest.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url' +import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' +import viteConfig from './vite.config' + +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + environment: 'jsdom', + exclude: [...configDefaults.exclude, 'e2e/**'], + root: fileURLToPath(new URL('./', import.meta.url)) + } + }) +) diff --git a/examples/custom-type-checked-rules-on-and-off/.editorconfig b/examples/custom-type-checked-rules-on-and-off/.editorconfig new file mode 100644 index 0000000..ecea360 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/.editorconfig @@ -0,0 +1,6 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/examples/custom-type-checked-rules-on-and-off/.gitignore b/examples/custom-type-checked-rules-on-and-off/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/custom-type-checked-rules-on-and-off/.vscode/extensions.json b/examples/custom-type-checked-rules-on-and-off/.vscode/extensions.json new file mode 100644 index 0000000..5efa012 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint", + "EditorConfig.EditorConfig" + ] +} diff --git a/examples/custom-type-checked-rules-on-and-off/README.md b/examples/custom-type-checked-rules-on-and-off/README.md new file mode 100644 index 0000000..2b1b07c --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/README.md @@ -0,0 +1,39 @@ +# custom-type-checked-rules-on-and-off + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/custom-type-checked-rules-on-and-off/env.d.ts b/examples/custom-type-checked-rules-on-and-off/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/custom-type-checked-rules-on-and-off/eslint.config.js b/examples/custom-type-checked-rules-on-and-off/eslint.config.js new file mode 100644 index 0000000..7ad3768 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/eslint.config.js @@ -0,0 +1,28 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommendedTypeChecked, + + { + files: ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.vue'], + rules: { + // With plain ESLint configs, the following rule will throw + // because some of the vue files can't be type-checked. + // But now it's handled by `defineConfigWithVueTs`. + '@typescript-eslint/require-array-sort-compare': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'off', + } + }, +) diff --git a/examples/custom-type-checked-rules-on-and-off/index.html b/examples/custom-type-checked-rules-on-and-off/index.html new file mode 100644 index 0000000..9e5fc8f --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/custom-type-checked-rules-on-and-off/package.json b/examples/custom-type-checked-rules-on-and-off/package.json new file mode 100644 index 0000000..2f6fa20 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/package.json @@ -0,0 +1,31 @@ +{ + "name": "custom-type-checked-rules-on-and-off", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.1", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:^", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vite-plugin-vue-devtools": "^7.7.2", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/custom-type-checked-rules-on-and-off/public/favicon.ico b/examples/custom-type-checked-rules-on-and-off/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/custom-type-checked-rules-on-and-off/public/favicon.ico differ diff --git a/examples/custom-type-checked-rules-on-and-off/src/App.vue b/examples/custom-type-checked-rules-on-and-off/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/custom-type-checked-rules-on-and-off/src/assets/base.css b/examples/custom-type-checked-rules-on-and-off/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/custom-type-checked-rules-on-and-off/src/assets/logo.svg b/examples/custom-type-checked-rules-on-and-off/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/custom-type-checked-rules-on-and-off/src/assets/main.css b/examples/custom-type-checked-rules-on-and-off/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/HelloWorld.vue b/examples/custom-type-checked-rules-on-and-off/src/components/HelloWorld.vue new file mode 100644 index 0000000..a2eabd1 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/TheWelcome.vue b/examples/custom-type-checked-rules-on-and-off/src/components/TheWelcome.vue new file mode 100644 index 0000000..674b490 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/TheWelcome.vue @@ -0,0 +1,94 @@ + + + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/WelcomeItem.vue b/examples/custom-type-checked-rules-on-and-off/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconCommunity.vue b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconDocumentation.vue b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconEcosystem.vue b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconSupport.vue b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconTooling.vue b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/custom-type-checked-rules-on-and-off/src/main.ts b/examples/custom-type-checked-rules-on-and-off/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/custom-type-checked-rules-on-and-off/tsconfig.app.json b/examples/custom-type-checked-rules-on-and-off/tsconfig.app.json new file mode 100644 index 0000000..913b8f2 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/custom-type-checked-rules-on-and-off/tsconfig.json b/examples/custom-type-checked-rules-on-and-off/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/custom-type-checked-rules-on-and-off/tsconfig.node.json b/examples/custom-type-checked-rules-on-and-off/tsconfig.node.json new file mode 100644 index 0000000..4c399c2 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/tsconfig.node.json @@ -0,0 +1,18 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/custom-type-checked-rules-on-and-off/vite.config.ts b/examples/custom-type-checked-rules-on-and-off/vite.config.ts new file mode 100644 index 0000000..4217010 --- /dev/null +++ b/examples/custom-type-checked-rules-on-and-off/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + }, + }, +}) diff --git a/examples/disable-ts-in-templates/.gitignore b/examples/disable-ts-in-templates/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/disable-ts-in-templates/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/disable-ts-in-templates/.vscode/extensions.json b/examples/disable-ts-in-templates/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/disable-ts-in-templates/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/disable-ts-in-templates/README.md b/examples/disable-ts-in-templates/README.md new file mode 100644 index 0000000..ebf2961 --- /dev/null +++ b/examples/disable-ts-in-templates/README.md @@ -0,0 +1,39 @@ +# disable-ts-in-templates + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/disable-ts-in-templates/env.d.ts b/examples/disable-ts-in-templates/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/disable-ts-in-templates/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/disable-ts-in-templates/eslint.config.js b/examples/disable-ts-in-templates/eslint.config.js new file mode 100644 index 0000000..c6b63eb --- /dev/null +++ b/examples/disable-ts-in-templates/eslint.config.js @@ -0,0 +1,25 @@ +import pluginVue from 'eslint-plugin-vue' +import { + configureVueProject, + defineConfigWithVueTs, + vueTsConfigs, +} from '@vue/eslint-config-typescript' + +configureVueProject({ + tsSyntaxInTemplates: false, +}) + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/examples/disable-ts-in-templates/index.html b/examples/disable-ts-in-templates/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/disable-ts-in-templates/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/disable-ts-in-templates/package.json b/examples/disable-ts-in-templates/package.json new file mode 100644 index 0000000..42d71af --- /dev/null +++ b/examples/disable-ts-in-templates/package.json @@ -0,0 +1,30 @@ +{ + "name": "disable-ts-in-templates", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/disable-ts-in-templates/public/favicon.ico b/examples/disable-ts-in-templates/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/disable-ts-in-templates/public/favicon.ico differ diff --git a/examples/disable-ts-in-templates/src/App.vue b/examples/disable-ts-in-templates/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/disable-ts-in-templates/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/disable-ts-in-templates/src/assets/base.css b/examples/disable-ts-in-templates/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/disable-ts-in-templates/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/disable-ts-in-templates/src/assets/logo.svg b/examples/disable-ts-in-templates/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/disable-ts-in-templates/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/disable-ts-in-templates/src/assets/main.css b/examples/disable-ts-in-templates/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/disable-ts-in-templates/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/disable-ts-in-templates/src/components/HelloWorld.vue b/examples/disable-ts-in-templates/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/disable-ts-in-templates/src/components/TheWelcome.vue b/examples/disable-ts-in-templates/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/disable-ts-in-templates/src/components/WelcomeItem.vue b/examples/disable-ts-in-templates/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/disable-ts-in-templates/src/components/icons/IconCommunity.vue b/examples/disable-ts-in-templates/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-ts-in-templates/src/components/icons/IconDocumentation.vue b/examples/disable-ts-in-templates/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-ts-in-templates/src/components/icons/IconEcosystem.vue b/examples/disable-ts-in-templates/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-ts-in-templates/src/components/icons/IconSupport.vue b/examples/disable-ts-in-templates/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-ts-in-templates/src/components/icons/IconTooling.vue b/examples/disable-ts-in-templates/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/disable-ts-in-templates/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/disable-ts-in-templates/src/main.ts b/examples/disable-ts-in-templates/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/disable-ts-in-templates/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/disable-ts-in-templates/tsconfig.app.json b/examples/disable-ts-in-templates/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/disable-ts-in-templates/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/disable-ts-in-templates/tsconfig.json b/examples/disable-ts-in-templates/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/disable-ts-in-templates/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/disable-ts-in-templates/tsconfig.node.json b/examples/disable-ts-in-templates/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/disable-ts-in-templates/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/disable-ts-in-templates/vite.config.ts b/examples/disable-ts-in-templates/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/disable-ts-in-templates/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/disable-type-checked-for-yml/.editorconfig b/examples/disable-type-checked-for-yml/.editorconfig new file mode 100644 index 0000000..ecea360 --- /dev/null +++ b/examples/disable-type-checked-for-yml/.editorconfig @@ -0,0 +1,6 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/examples/disable-type-checked-for-yml/.gitignore b/examples/disable-type-checked-for-yml/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/disable-type-checked-for-yml/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/disable-type-checked-for-yml/.prettierrc.json b/examples/disable-type-checked-for-yml/.prettierrc.json new file mode 100644 index 0000000..effc164 --- /dev/null +++ b/examples/disable-type-checked-for-yml/.prettierrc.json @@ -0,0 +1,7 @@ + +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "singleQuote": true, + "arrowParens": "avoid" +} diff --git a/examples/disable-type-checked-for-yml/.vscode/extensions.json b/examples/disable-type-checked-for-yml/.vscode/extensions.json new file mode 100644 index 0000000..de51a0a --- /dev/null +++ b/examples/disable-type-checked-for-yml/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "Vue.volar", + "vitest.explorer", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/examples/disable-type-checked-for-yml/README.md b/examples/disable-type-checked-for-yml/README.md new file mode 100644 index 0000000..64ea94a --- /dev/null +++ b/examples/disable-type-checked-for-yml/README.md @@ -0,0 +1,61 @@ +# disable-type-checked-for-yml + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run Unit Tests with [Vitest](https://vitest.dev/) + +```sh +npm run test:unit +``` + +### Run End-to-End Tests with [Cypress](https://www.cypress.io/) + +```sh +npm run test:e2e:dev +``` + +This runs the end-to-end tests against the Vite development server. +It is much faster than the production build. + +But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments): + +```sh +npm run build +npm run test:e2e +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/disable-type-checked-for-yml/cypress.config.ts b/examples/disable-type-checked-for-yml/cypress.config.ts new file mode 100644 index 0000000..0f66080 --- /dev/null +++ b/examples/disable-type-checked-for-yml/cypress.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}', + baseUrl: 'http://localhost:4173' + } +}) diff --git a/examples/disable-type-checked-for-yml/cypress/e2e/example.cy.ts b/examples/disable-type-checked-for-yml/cypress/e2e/example.cy.ts new file mode 100644 index 0000000..7554c35 --- /dev/null +++ b/examples/disable-type-checked-for-yml/cypress/e2e/example.cy.ts @@ -0,0 +1,8 @@ +// https://on.cypress.io/api + +describe('My First Test', () => { + it('visits the app root url', () => { + cy.visit('/') + cy.contains('h1', 'You did it!') + }) +}) diff --git a/examples/disable-type-checked-for-yml/cypress/fixtures/example.json b/examples/disable-type-checked-for-yml/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/examples/disable-type-checked-for-yml/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/examples/disable-type-checked-for-yml/cypress/support/commands.ts b/examples/disable-type-checked-for-yml/cypress/support/commands.ts new file mode 100644 index 0000000..9b7bb8e --- /dev/null +++ b/examples/disable-type-checked-for-yml/cypress/support/commands.ts @@ -0,0 +1,39 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } + +export {} diff --git a/examples/disable-type-checked-for-yml/cypress/support/e2e.ts b/examples/disable-type-checked-for-yml/cypress/support/e2e.ts new file mode 100644 index 0000000..d68db96 --- /dev/null +++ b/examples/disable-type-checked-for-yml/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/examples/disable-type-checked-for-yml/cypress/tsconfig.json b/examples/disable-type-checked-for-yml/cypress/tsconfig.json new file mode 100644 index 0000000..a13c5d6 --- /dev/null +++ b/examples/disable-type-checked-for-yml/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["./e2e/**/*", "./support/**/*"], + "compilerOptions": { + "isolatedModules": false, + "types": ["cypress"] + } +} diff --git a/examples/disable-type-checked-for-yml/env.d.ts b/examples/disable-type-checked-for-yml/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/disable-type-checked-for-yml/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/disable-type-checked-for-yml/eslint.config.js b/examples/disable-type-checked-for-yml/eslint.config.js new file mode 100644 index 0000000..43ab449 --- /dev/null +++ b/examples/disable-type-checked-for-yml/eslint.config.js @@ -0,0 +1,42 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' +import pluginVitest from '@vitest/eslint-plugin' +import pluginCypress from 'eslint-plugin-cypress/flat' +import pluginYml from 'eslint-plugin-yml'; +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue,yml,yaml}'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommendedTypeChecked, + + { + ...pluginVitest.configs.recommended, + files: ['src/**/__tests__/*'], + }, + + { + ...pluginCypress.configs.recommended, + files: [ + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}', + ], + }, + skipFormatting, + + ...pluginYml.configs['flat/recommended'], + + { + files: ["**/*.yml", "**/*.yaml"], + extends: [vueTsConfigs.disableTypeChecked], + }, +) diff --git a/examples/disable-type-checked-for-yml/index.html b/examples/disable-type-checked-for-yml/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/disable-type-checked-for-yml/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/disable-type-checked-for-yml/package.json b/examples/disable-type-checked-for-yml/package.json new file mode 100644 index 0000000..aea8986 --- /dev/null +++ b/examples/disable-type-checked-for-yml/package.json @@ -0,0 +1,49 @@ +{ + "name": "disable-type-checked-for-yml", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:unit": "vitest", + "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'", + "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix", + "format": "prettier --write src/" + }, + "dependencies": { + "pinia": "^3.0.1", + "vue": "^3.5.13", + "vue-router": "^4.5.0" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/jsdom": "^21.1.7", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vitest/eslint-plugin": "^1.1.38", + "@vue/eslint-config-prettier": "^10.2.0", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.7.0", + "cypress": "^14.2.1", + "eslint": "^9.23.0", + "eslint-plugin-cypress": "^4.2.0", + "eslint-plugin-vue": "~10.0.0", + "eslint-plugin-yml": "^1.17.0", + "jsdom": "^26.0.0", + "npm-run-all2": "^7.0.2", + "prettier": "3.5.3", + "start-server-and-test": "^2.0.11", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vite-plugin-vue-devtools": "^7.7.2", + "vitest": "^3.1.1", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/disable-type-checked-for-yml/public/favicon.ico b/examples/disable-type-checked-for-yml/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/disable-type-checked-for-yml/public/favicon.ico differ diff --git a/examples/disable-type-checked-for-yml/src/App.vue b/examples/disable-type-checked-for-yml/src/App.vue new file mode 100644 index 0000000..7905b05 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/App.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/examples/disable-type-checked-for-yml/src/assets/base.css b/examples/disable-type-checked-for-yml/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/disable-type-checked-for-yml/src/assets/logo.svg b/examples/disable-type-checked-for-yml/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/disable-type-checked-for-yml/src/assets/main.css b/examples/disable-type-checked-for-yml/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/disable-type-checked-for-yml/src/components/HelloWorld.vue b/examples/disable-type-checked-for-yml/src/components/HelloWorld.vue new file mode 100644 index 0000000..d174cf8 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/disable-type-checked-for-yml/src/components/TheWelcome.vue b/examples/disable-type-checked-for-yml/src/components/TheWelcome.vue new file mode 100644 index 0000000..e65a66b --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/disable-type-checked-for-yml/src/components/WelcomeItem.vue b/examples/disable-type-checked-for-yml/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/disable-type-checked-for-yml/src/components/__tests__/HelloWorld.spec.ts b/examples/disable-type-checked-for-yml/src/components/__tests__/HelloWorld.spec.ts new file mode 100644 index 0000000..2533202 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/__tests__/HelloWorld.spec.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest' + +import { mount } from '@vue/test-utils' +import HelloWorld from '../HelloWorld.vue' + +describe('HelloWorld', () => { + it('renders properly', () => { + const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) + expect(wrapper.text()).toContain('Hello Vitest') + }) +}) diff --git a/examples/disable-type-checked-for-yml/src/components/icons/IconCommunity.vue b/examples/disable-type-checked-for-yml/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-type-checked-for-yml/src/components/icons/IconDocumentation.vue b/examples/disable-type-checked-for-yml/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-type-checked-for-yml/src/components/icons/IconEcosystem.vue b/examples/disable-type-checked-for-yml/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-type-checked-for-yml/src/components/icons/IconSupport.vue b/examples/disable-type-checked-for-yml/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/disable-type-checked-for-yml/src/components/icons/IconTooling.vue b/examples/disable-type-checked-for-yml/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/disable-type-checked-for-yml/src/issue-136.yml b/examples/disable-type-checked-for-yml/src/issue-136.yml new file mode 100644 index 0000000..a818c6f --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/issue-136.yml @@ -0,0 +1 @@ +just: some random yaml fields diff --git a/examples/disable-type-checked-for-yml/src/main.ts b/examples/disable-type-checked-for-yml/src/main.ts new file mode 100644 index 0000000..5dcad83 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/main.ts @@ -0,0 +1,14 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) + +app.mount('#app') diff --git a/examples/disable-type-checked-for-yml/src/router/index.ts b/examples/disable-type-checked-for-yml/src/router/index.ts new file mode 100644 index 0000000..ce51fcf --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/router/index.ts @@ -0,0 +1,24 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' +import type { Component } from 'vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: async (): Promise<{ default: Component }> => import('../views/AboutView.vue') + } + ] +}) + +export default router diff --git a/examples/disable-type-checked-for-yml/src/stores/counter.ts b/examples/disable-type-checked-for-yml/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/examples/disable-type-checked-for-yml/src/views/AboutView.vue b/examples/disable-type-checked-for-yml/src/views/AboutView.vue new file mode 100644 index 0000000..756ad2a --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/views/AboutView.vue @@ -0,0 +1,15 @@ + + + diff --git a/examples/disable-type-checked-for-yml/src/views/HomeView.vue b/examples/disable-type-checked-for-yml/src/views/HomeView.vue new file mode 100644 index 0000000..d5c0217 --- /dev/null +++ b/examples/disable-type-checked-for-yml/src/views/HomeView.vue @@ -0,0 +1,9 @@ + + + diff --git a/examples/disable-type-checked-for-yml/tsconfig.app.json b/examples/disable-type-checked-for-yml/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/disable-type-checked-for-yml/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/disable-type-checked-for-yml/tsconfig.json b/examples/disable-type-checked-for-yml/tsconfig.json new file mode 100644 index 0000000..5304731 --- /dev/null +++ b/examples/disable-type-checked-for-yml/tsconfig.json @@ -0,0 +1,17 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ], + "compilerOptions": { + "module": "NodeNext" + } +} diff --git a/examples/disable-type-checked-for-yml/tsconfig.node.json b/examples/disable-type-checked-for-yml/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/disable-type-checked-for-yml/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/disable-type-checked-for-yml/tsconfig.vitest.json b/examples/disable-type-checked-for-yml/tsconfig.vitest.json new file mode 100644 index 0000000..571995d --- /dev/null +++ b/examples/disable-type-checked-for-yml/tsconfig.vitest.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.app.json", + "exclude": [], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo", + + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/examples/disable-type-checked-for-yml/vite.config.ts b/examples/disable-type-checked-for-yml/vite.config.ts new file mode 100644 index 0000000..c036b6f --- /dev/null +++ b/examples/disable-type-checked-for-yml/vite.config.ts @@ -0,0 +1,20 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/disable-type-checked-for-yml/vitest.config.ts b/examples/disable-type-checked-for-yml/vitest.config.ts new file mode 100644 index 0000000..4b1c897 --- /dev/null +++ b/examples/disable-type-checked-for-yml/vitest.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url' +import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' +import viteConfig from './vite.config' + +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + environment: 'jsdom', + exclude: [...configDefaults.exclude, 'e2e/**'], + root: fileURLToPath(new URL('./', import.meta.url)) + } + }) +) diff --git a/examples/minimal/.gitignore b/examples/minimal/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/minimal/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/minimal/.vscode/extensions.json b/examples/minimal/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/minimal/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/minimal/README.md b/examples/minimal/README.md new file mode 100644 index 0000000..a2f51a1 --- /dev/null +++ b/examples/minimal/README.md @@ -0,0 +1,39 @@ +# minimal + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/minimal/env.d.ts b/examples/minimal/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/minimal/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/minimal/eslint.config.js b/examples/minimal/eslint.config.js new file mode 100644 index 0000000..bd0d8bf --- /dev/null +++ b/examples/minimal/eslint.config.js @@ -0,0 +1,17 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/examples/minimal/index.html b/examples/minimal/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/minimal/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/minimal/package.json b/examples/minimal/package.json new file mode 100644 index 0000000..6216c8a --- /dev/null +++ b/examples/minimal/package.json @@ -0,0 +1,30 @@ +{ + "name": "minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/minimal/public/favicon.ico b/examples/minimal/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/minimal/public/favicon.ico differ diff --git a/examples/minimal/src/App.vue b/examples/minimal/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/minimal/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/minimal/src/assets/base.css b/examples/minimal/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/minimal/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/minimal/src/assets/logo.svg b/examples/minimal/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/minimal/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/minimal/src/assets/main.css b/examples/minimal/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/minimal/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/minimal/src/components/HelloWorld.vue b/examples/minimal/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/minimal/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/minimal/src/components/TheWelcome.vue b/examples/minimal/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/minimal/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/minimal/src/components/WelcomeItem.vue b/examples/minimal/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/minimal/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/minimal/src/components/icons/IconCommunity.vue b/examples/minimal/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/minimal/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/minimal/src/components/icons/IconDocumentation.vue b/examples/minimal/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/minimal/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/minimal/src/components/icons/IconEcosystem.vue b/examples/minimal/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/minimal/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/minimal/src/components/icons/IconSupport.vue b/examples/minimal/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/minimal/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/minimal/src/components/icons/IconTooling.vue b/examples/minimal/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/minimal/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/minimal/src/main.ts b/examples/minimal/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/minimal/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/minimal/tsconfig.app.json b/examples/minimal/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/minimal/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/minimal/tsconfig.json b/examples/minimal/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/minimal/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/minimal/tsconfig.node.json b/examples/minimal/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/minimal/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/minimal/vite.config.ts b/examples/minimal/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/minimal/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/type-checked/.editorconfig b/examples/type-checked/.editorconfig new file mode 100644 index 0000000..ecea360 --- /dev/null +++ b/examples/type-checked/.editorconfig @@ -0,0 +1,6 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/examples/type-checked/.gitignore b/examples/type-checked/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/type-checked/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/type-checked/.prettierrc.json b/examples/type-checked/.prettierrc.json new file mode 100644 index 0000000..effc164 --- /dev/null +++ b/examples/type-checked/.prettierrc.json @@ -0,0 +1,7 @@ + +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "singleQuote": true, + "arrowParens": "avoid" +} diff --git a/examples/type-checked/.vscode/extensions.json b/examples/type-checked/.vscode/extensions.json new file mode 100644 index 0000000..de51a0a --- /dev/null +++ b/examples/type-checked/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "Vue.volar", + "vitest.explorer", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/examples/type-checked/README.md b/examples/type-checked/README.md new file mode 100644 index 0000000..1f3dd9e --- /dev/null +++ b/examples/type-checked/README.md @@ -0,0 +1,61 @@ +# type-checked + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run Unit Tests with [Vitest](https://vitest.dev/) + +```sh +npm run test:unit +``` + +### Run End-to-End Tests with [Cypress](https://www.cypress.io/) + +```sh +npm run test:e2e:dev +``` + +This runs the end-to-end tests against the Vite development server. +It is much faster than the production build. + +But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments): + +```sh +npm run build +npm run test:e2e +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/type-checked/cypress.config.ts b/examples/type-checked/cypress.config.ts new file mode 100644 index 0000000..0f66080 --- /dev/null +++ b/examples/type-checked/cypress.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}', + baseUrl: 'http://localhost:4173' + } +}) diff --git a/examples/type-checked/cypress/e2e/example.cy.ts b/examples/type-checked/cypress/e2e/example.cy.ts new file mode 100644 index 0000000..7554c35 --- /dev/null +++ b/examples/type-checked/cypress/e2e/example.cy.ts @@ -0,0 +1,8 @@ +// https://on.cypress.io/api + +describe('My First Test', () => { + it('visits the app root url', () => { + cy.visit('/') + cy.contains('h1', 'You did it!') + }) +}) diff --git a/examples/type-checked/cypress/fixtures/example.json b/examples/type-checked/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/examples/type-checked/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/examples/type-checked/cypress/support/commands.ts b/examples/type-checked/cypress/support/commands.ts new file mode 100644 index 0000000..9b7bb8e --- /dev/null +++ b/examples/type-checked/cypress/support/commands.ts @@ -0,0 +1,39 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } + +export {} diff --git a/examples/type-checked/cypress/support/e2e.ts b/examples/type-checked/cypress/support/e2e.ts new file mode 100644 index 0000000..d68db96 --- /dev/null +++ b/examples/type-checked/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/examples/type-checked/cypress/tsconfig.json b/examples/type-checked/cypress/tsconfig.json new file mode 100644 index 0000000..a13c5d6 --- /dev/null +++ b/examples/type-checked/cypress/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["./e2e/**/*", "./support/**/*"], + "compilerOptions": { + "isolatedModules": false, + "types": ["cypress"] + } +} diff --git a/examples/type-checked/env.d.ts b/examples/type-checked/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/type-checked/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/type-checked/eslint.config.js b/examples/type-checked/eslint.config.js new file mode 100644 index 0000000..456b067 --- /dev/null +++ b/examples/type-checked/eslint.config.js @@ -0,0 +1,47 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' +import pluginVitest from '@vitest/eslint-plugin' +import pluginCypress from 'eslint-plugin-cypress/flat' +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.strictTypeChecked, + { + name: 'overrides', + files: ['**/*.{ts,vue}'], + rules: { + '@typescript-eslint/restrict-template-expressions': [ + 'error', + { + allowNumber: true, + allowBoolean: true, + }, + ], + }, + }, + + { + ...pluginVitest.configs.recommended, + files: ['src/**/__tests__/*'], + }, + + { + ...pluginCypress.configs.recommended, + files: [ + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}', + ], + }, + skipFormatting, +) diff --git a/examples/type-checked/index.html b/examples/type-checked/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/type-checked/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/type-checked/package.json b/examples/type-checked/package.json new file mode 100644 index 0000000..cde83b8 --- /dev/null +++ b/examples/type-checked/package.json @@ -0,0 +1,48 @@ +{ + "name": "type-checked", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:unit": "vitest", + "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'", + "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix", + "format": "prettier --write src/" + }, + "dependencies": { + "pinia": "^3.0.1", + "vue": "^3.5.13", + "vue-router": "^4.5.0" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/jsdom": "^21.1.7", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vitest/eslint-plugin": "^1.1.38", + "@vue/eslint-config-prettier": "^10.2.0", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.7.0", + "cypress": "^14.2.1", + "eslint": "^9.23.0", + "eslint-plugin-cypress": "^4.2.0", + "eslint-plugin-vue": "~10.0.0", + "jsdom": "^26.0.0", + "npm-run-all2": "^7.0.2", + "prettier": "3.5.3", + "start-server-and-test": "^2.0.11", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vite-plugin-vue-devtools": "^7.7.2", + "vitest": "^3.1.1", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/type-checked/public/favicon.ico b/examples/type-checked/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/type-checked/public/favicon.ico differ diff --git a/examples/type-checked/src/App.vue b/examples/type-checked/src/App.vue new file mode 100644 index 0000000..7905b05 --- /dev/null +++ b/examples/type-checked/src/App.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/examples/type-checked/src/assets/base.css b/examples/type-checked/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/type-checked/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/type-checked/src/assets/logo.svg b/examples/type-checked/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/type-checked/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/type-checked/src/assets/main.css b/examples/type-checked/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/type-checked/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/type-checked/src/components/HelloWorld.vue b/examples/type-checked/src/components/HelloWorld.vue new file mode 100644 index 0000000..d174cf8 --- /dev/null +++ b/examples/type-checked/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/type-checked/src/components/TheWelcome.vue b/examples/type-checked/src/components/TheWelcome.vue new file mode 100644 index 0000000..e65a66b --- /dev/null +++ b/examples/type-checked/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/type-checked/src/components/WelcomeItem.vue b/examples/type-checked/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/type-checked/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/type-checked/src/components/__tests__/HelloWorld.spec.ts b/examples/type-checked/src/components/__tests__/HelloWorld.spec.ts new file mode 100644 index 0000000..2533202 --- /dev/null +++ b/examples/type-checked/src/components/__tests__/HelloWorld.spec.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest' + +import { mount } from '@vue/test-utils' +import HelloWorld from '../HelloWorld.vue' + +describe('HelloWorld', () => { + it('renders properly', () => { + const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) + expect(wrapper.text()).toContain('Hello Vitest') + }) +}) diff --git a/examples/type-checked/src/components/icons/IconCommunity.vue b/examples/type-checked/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/type-checked/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/type-checked/src/components/icons/IconDocumentation.vue b/examples/type-checked/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/type-checked/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/type-checked/src/components/icons/IconEcosystem.vue b/examples/type-checked/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/type-checked/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/type-checked/src/components/icons/IconSupport.vue b/examples/type-checked/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/type-checked/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/type-checked/src/components/icons/IconTooling.vue b/examples/type-checked/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/type-checked/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/type-checked/src/main.ts b/examples/type-checked/src/main.ts new file mode 100644 index 0000000..5dcad83 --- /dev/null +++ b/examples/type-checked/src/main.ts @@ -0,0 +1,14 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import { createPinia } from 'pinia' + +import App from './App.vue' +import router from './router' + +const app = createApp(App) + +app.use(createPinia()) +app.use(router) + +app.mount('#app') diff --git a/examples/type-checked/src/router/index.ts b/examples/type-checked/src/router/index.ts new file mode 100644 index 0000000..ce51fcf --- /dev/null +++ b/examples/type-checked/src/router/index.ts @@ -0,0 +1,24 @@ +import { createRouter, createWebHistory } from 'vue-router' +import HomeView from '../views/HomeView.vue' +import type { Component } from 'vue' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: async (): Promise<{ default: Component }> => import('../views/AboutView.vue') + } + ] +}) + +export default router diff --git a/examples/type-checked/src/stores/counter.ts b/examples/type-checked/src/stores/counter.ts new file mode 100644 index 0000000..b6757ba --- /dev/null +++ b/examples/type-checked/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { ref, computed } from 'vue' +import { defineStore } from 'pinia' + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0) + const doubleCount = computed(() => count.value * 2) + function increment() { + count.value++ + } + + return { count, doubleCount, increment } +}) diff --git a/examples/type-checked/src/views/AboutView.vue b/examples/type-checked/src/views/AboutView.vue new file mode 100644 index 0000000..756ad2a --- /dev/null +++ b/examples/type-checked/src/views/AboutView.vue @@ -0,0 +1,15 @@ + + + diff --git a/examples/type-checked/src/views/HomeView.vue b/examples/type-checked/src/views/HomeView.vue new file mode 100644 index 0000000..d5c0217 --- /dev/null +++ b/examples/type-checked/src/views/HomeView.vue @@ -0,0 +1,9 @@ + + + diff --git a/examples/type-checked/tsconfig.app.json b/examples/type-checked/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/type-checked/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/type-checked/tsconfig.json b/examples/type-checked/tsconfig.json new file mode 100644 index 0000000..5304731 --- /dev/null +++ b/examples/type-checked/tsconfig.json @@ -0,0 +1,17 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ], + "compilerOptions": { + "module": "NodeNext" + } +} diff --git a/examples/type-checked/tsconfig.node.json b/examples/type-checked/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/type-checked/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/type-checked/tsconfig.vitest.json b/examples/type-checked/tsconfig.vitest.json new file mode 100644 index 0000000..571995d --- /dev/null +++ b/examples/type-checked/tsconfig.vitest.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.app.json", + "exclude": [], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo", + + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/examples/type-checked/vite.config.ts b/examples/type-checked/vite.config.ts new file mode 100644 index 0000000..c036b6f --- /dev/null +++ b/examples/type-checked/vite.config.ts @@ -0,0 +1,20 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/type-checked/vitest.config.ts b/examples/type-checked/vitest.config.ts new file mode 100644 index 0000000..4b1c897 --- /dev/null +++ b/examples/type-checked/vitest.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url' +import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' +import viteConfig from './vite.config' + +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + environment: 'jsdom', + exclude: [...configDefaults.exclude, 'e2e/**'], + root: fileURLToPath(new URL('./', import.meta.url)) + } + }) +) diff --git a/examples/with-cypress/.gitignore b/examples/with-cypress/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-cypress/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-cypress/.vscode/extensions.json b/examples/with-cypress/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/with-cypress/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-cypress/README.md b/examples/with-cypress/README.md new file mode 100644 index 0000000..6b48baa --- /dev/null +++ b/examples/with-cypress/README.md @@ -0,0 +1,61 @@ +# with-cypress + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run Headed Component Tests with [Cypress Component Testing](https://on.cypress.io/component) + +```sh +npm run test:unit:dev # or `npm run test:unit` for headless testing +``` + +### Run End-to-End Tests with [Cypress](https://www.cypress.io/) + +```sh +npm run test:e2e:dev +``` + +This runs the end-to-end tests against the Vite development server. +It is much faster than the production build. + +But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments): + +```sh +npm run build +npm run test:e2e +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-cypress/cypress.config.ts b/examples/with-cypress/cypress.config.ts new file mode 100644 index 0000000..c8fac12 --- /dev/null +++ b/examples/with-cypress/cypress.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'cypress' + +export default defineConfig({ + e2e: { + specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}', + baseUrl: 'http://localhost:4173' + }, + component: { + specPattern: 'src/**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', + devServer: { + framework: 'vue', + bundler: 'vite' + } + } +}) diff --git a/examples/with-cypress/cypress/e2e/example.cy.ts b/examples/with-cypress/cypress/e2e/example.cy.ts new file mode 100644 index 0000000..7554c35 --- /dev/null +++ b/examples/with-cypress/cypress/e2e/example.cy.ts @@ -0,0 +1,8 @@ +// https://on.cypress.io/api + +describe('My First Test', () => { + it('visits the app root url', () => { + cy.visit('/') + cy.contains('h1', 'You did it!') + }) +}) diff --git a/examples/with-cypress/cypress/e2e/tsconfig.json b/examples/with-cypress/cypress/e2e/tsconfig.json new file mode 100644 index 0000000..c94f1d4 --- /dev/null +++ b/examples/with-cypress/cypress/e2e/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["./**/*", "../support/**/*"], + "compilerOptions": { + "isolatedModules": false, + "types": ["cypress"] + } +} diff --git a/examples/with-cypress/cypress/fixtures/example.json b/examples/with-cypress/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/examples/with-cypress/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/examples/with-cypress/cypress/support/commands.ts b/examples/with-cypress/cypress/support/commands.ts new file mode 100644 index 0000000..9b7bb8e --- /dev/null +++ b/examples/with-cypress/cypress/support/commands.ts @@ -0,0 +1,39 @@ +/// +// *********************************************** +// This example commands.ts shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add('login', (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) +// +// declare global { +// namespace Cypress { +// interface Chainable { +// login(email: string, password: string): Chainable +// drag(subject: string, options?: Partial): Chainable +// dismiss(subject: string, options?: Partial): Chainable +// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable +// } +// } +// } + +export {} diff --git a/examples/with-cypress/cypress/support/component-index.html b/examples/with-cypress/cypress/support/component-index.html new file mode 100644 index 0000000..5f9622a --- /dev/null +++ b/examples/with-cypress/cypress/support/component-index.html @@ -0,0 +1,12 @@ + + + + + + + Components App + + +
+ + diff --git a/examples/with-cypress/cypress/support/component.ts b/examples/with-cypress/cypress/support/component.ts new file mode 100644 index 0000000..04e4c35 --- /dev/null +++ b/examples/with-cypress/cypress/support/component.ts @@ -0,0 +1,43 @@ +// *********************************************************** +// This example support/component.ts is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') + +// Import global styles +import '@/assets/main.css' + +import { mount } from 'cypress/vue' + +// Augment the Cypress namespace to include type definitions for +// your custom command. +// Alternatively, can be defined in cypress/support/component.d.ts +// with a at the top of your spec. +/* eslint-disable @typescript-eslint/no-namespace */ +declare global { + namespace Cypress { + interface Chainable { + mount: typeof mount + } + } +} + +Cypress.Commands.add('mount', mount) + +// Example use: +// cy.mount(MyComponent) diff --git a/examples/with-cypress/cypress/support/e2e.ts b/examples/with-cypress/cypress/support/e2e.ts new file mode 100644 index 0000000..d68db96 --- /dev/null +++ b/examples/with-cypress/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/examples/with-cypress/env.d.ts b/examples/with-cypress/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-cypress/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-cypress/eslint.config.js b/examples/with-cypress/eslint.config.js new file mode 100644 index 0000000..d7ffa15 --- /dev/null +++ b/examples/with-cypress/eslint.config.js @@ -0,0 +1,27 @@ +import pluginVue from 'eslint-plugin-vue' +import pluginCypress from 'eslint-plugin-cypress/flat' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, + + { + ...pluginCypress.configs.recommended, + files: [ + '**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}', + ], + }, +) diff --git a/examples/with-cypress/index.html b/examples/with-cypress/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-cypress/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-cypress/package.json b/examples/with-cypress/package.json new file mode 100644 index 0000000..41c6abb --- /dev/null +++ b/examples/with-cypress/package.json @@ -0,0 +1,37 @@ +{ + "name": "with-cypress", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'", + "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'", + "test:unit": "cypress run --component", + "test:unit:dev": "cypress open --component", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "cypress": "^14.2.1", + "eslint": "^9.23.0", + "eslint-plugin-cypress": "^4.2.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "start-server-and-test": "^2.0.11", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-cypress/public/favicon.ico b/examples/with-cypress/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-cypress/public/favicon.ico differ diff --git a/examples/with-cypress/src/App.vue b/examples/with-cypress/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-cypress/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-cypress/src/assets/base.css b/examples/with-cypress/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-cypress/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-cypress/src/assets/logo.svg b/examples/with-cypress/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-cypress/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-cypress/src/assets/main.css b/examples/with-cypress/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-cypress/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-cypress/src/components/HelloWorld.vue b/examples/with-cypress/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-cypress/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-cypress/src/components/TheWelcome.vue b/examples/with-cypress/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-cypress/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-cypress/src/components/WelcomeItem.vue b/examples/with-cypress/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-cypress/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-cypress/src/components/__tests__/HelloWorld.cy.ts b/examples/with-cypress/src/components/__tests__/HelloWorld.cy.ts new file mode 100644 index 0000000..535a0e5 --- /dev/null +++ b/examples/with-cypress/src/components/__tests__/HelloWorld.cy.ts @@ -0,0 +1,12 @@ +import HelloWorld from '../HelloWorld.vue' + +describe('HelloWorld', () => { + it('playground', () => { + cy.mount(HelloWorld, { props: { msg: 'Hello Cypress' } }) + }) + + it('renders properly', () => { + cy.mount(HelloWorld, { props: { msg: 'Hello Cypress' } }) + cy.get('h1').should('contain', 'Hello Cypress') + }) +}) diff --git a/examples/with-cypress/src/components/icons/IconCommunity.vue b/examples/with-cypress/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-cypress/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-cypress/src/components/icons/IconDocumentation.vue b/examples/with-cypress/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-cypress/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-cypress/src/components/icons/IconEcosystem.vue b/examples/with-cypress/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-cypress/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-cypress/src/components/icons/IconSupport.vue b/examples/with-cypress/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-cypress/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-cypress/src/components/icons/IconTooling.vue b/examples/with-cypress/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-cypress/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-cypress/src/main.ts b/examples/with-cypress/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-cypress/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-cypress/tsconfig.app.json b/examples/with-cypress/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-cypress/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-cypress/tsconfig.cypress-ct.json b/examples/with-cypress/tsconfig.cypress-ct.json new file mode 100644 index 0000000..12833b2 --- /dev/null +++ b/examples/with-cypress/tsconfig.cypress-ct.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.app.json", + "include": [ + "env.d.ts", + "src/**/*", + "src/**/*.vue", + "cypress/support/component.*", + "cypress/support/commands.ts" + ], + "exclude": [], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.cypress-ct.tsbuildinfo" + } +} diff --git a/examples/with-cypress/tsconfig.json b/examples/with-cypress/tsconfig.json new file mode 100644 index 0000000..d3b6c31 --- /dev/null +++ b/examples/with-cypress/tsconfig.json @@ -0,0 +1,17 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.cypress-ct.json" + } + ], + "compilerOptions": { + "module": "NodeNext" + } +} diff --git a/examples/with-cypress/tsconfig.node.json b/examples/with-cypress/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-cypress/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-cypress/vite.config.ts b/examples/with-cypress/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/with-cypress/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-jsx-in-vue/.gitignore b/examples/with-jsx-in-vue/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-jsx-in-vue/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-jsx-in-vue/.vscode/extensions.json b/examples/with-jsx-in-vue/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/with-jsx-in-vue/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-jsx-in-vue/README.md b/examples/with-jsx-in-vue/README.md new file mode 100644 index 0000000..92131c7 --- /dev/null +++ b/examples/with-jsx-in-vue/README.md @@ -0,0 +1,39 @@ +# with-jsx-in-vue + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-jsx-in-vue/env.d.ts b/examples/with-jsx-in-vue/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-jsx-in-vue/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-jsx-in-vue/eslint.config.js b/examples/with-jsx-in-vue/eslint.config.js new file mode 100644 index 0000000..91e727b --- /dev/null +++ b/examples/with-jsx-in-vue/eslint.config.js @@ -0,0 +1,31 @@ +import pluginVue from 'eslint-plugin-vue' +import { + defineConfigWithVueTs, + vueTsConfigs, + configureVueProject, +} from '@vue/eslint-config-typescript' + +configureVueProject({ scriptLangs: ['js', 'jsx', 'ts', 'tsx'] }) + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: [ + '**/*.js', + '**/*.mjs', + '**/*.jsx', + '**/*.ts', + '**/*.mts', + '**/*.tsx', + '**/*.vue', + ], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/examples/with-jsx-in-vue/index.html b/examples/with-jsx-in-vue/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-jsx-in-vue/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-jsx-in-vue/package.json b/examples/with-jsx-in-vue/package.json new file mode 100644 index 0000000..858a799 --- /dev/null +++ b/examples/with-jsx-in-vue/package.json @@ -0,0 +1,31 @@ +{ + "name": "with-jsx-in-vue", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-jsx-in-vue/public/favicon.ico b/examples/with-jsx-in-vue/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-jsx-in-vue/public/favicon.ico differ diff --git a/examples/with-jsx-in-vue/src/App.vue b/examples/with-jsx-in-vue/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-jsx-in-vue/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-jsx-in-vue/src/assets/base.css b/examples/with-jsx-in-vue/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-jsx-in-vue/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-jsx-in-vue/src/assets/logo.svg b/examples/with-jsx-in-vue/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-jsx-in-vue/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-jsx-in-vue/src/assets/main.css b/examples/with-jsx-in-vue/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-jsx-in-vue/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-jsx-in-vue/src/components/HelloWorld.vue b/examples/with-jsx-in-vue/src/components/HelloWorld.vue new file mode 100644 index 0000000..e8ea308 --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/HelloWorld.vue @@ -0,0 +1,50 @@ + + + diff --git a/examples/with-jsx-in-vue/src/components/TheWelcome.vue b/examples/with-jsx-in-vue/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-jsx-in-vue/src/components/WelcomeItem.vue b/examples/with-jsx-in-vue/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-jsx-in-vue/src/components/icons/IconCommunity.vue b/examples/with-jsx-in-vue/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx-in-vue/src/components/icons/IconDocumentation.vue b/examples/with-jsx-in-vue/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx-in-vue/src/components/icons/IconEcosystem.vue b/examples/with-jsx-in-vue/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx-in-vue/src/components/icons/IconSupport.vue b/examples/with-jsx-in-vue/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx-in-vue/src/components/icons/IconTooling.vue b/examples/with-jsx-in-vue/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-jsx-in-vue/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-jsx-in-vue/src/main.ts b/examples/with-jsx-in-vue/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-jsx-in-vue/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-jsx-in-vue/tsconfig.app.json b/examples/with-jsx-in-vue/tsconfig.app.json new file mode 100644 index 0000000..97926e7 --- /dev/null +++ b/examples/with-jsx-in-vue/tsconfig.app.json @@ -0,0 +1,17 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + + "allowJs": true, + "checkJs": true + } +} diff --git a/examples/with-jsx-in-vue/tsconfig.json b/examples/with-jsx-in-vue/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/with-jsx-in-vue/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/with-jsx-in-vue/tsconfig.node.json b/examples/with-jsx-in-vue/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-jsx-in-vue/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-jsx-in-vue/vite.config.ts b/examples/with-jsx-in-vue/vite.config.ts new file mode 100644 index 0000000..36c6187 --- /dev/null +++ b/examples/with-jsx-in-vue/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-jsx/.gitignore b/examples/with-jsx/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-jsx/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-jsx/.vscode/extensions.json b/examples/with-jsx/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/with-jsx/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-jsx/README.md b/examples/with-jsx/README.md new file mode 100644 index 0000000..2cab543 --- /dev/null +++ b/examples/with-jsx/README.md @@ -0,0 +1,39 @@ +# with-jsx + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-jsx/env.d.ts b/examples/with-jsx/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-jsx/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-jsx/eslint.config.js b/examples/with-jsx/eslint.config.js new file mode 100644 index 0000000..7fa9ba3 --- /dev/null +++ b/examples/with-jsx/eslint.config.js @@ -0,0 +1,17 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.js', '**/*.mjs', '**/*.jsx', '**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/examples/with-jsx/index.html b/examples/with-jsx/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-jsx/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-jsx/package.json b/examples/with-jsx/package.json new file mode 100644 index 0000000..f5801df --- /dev/null +++ b/examples/with-jsx/package.json @@ -0,0 +1,31 @@ +{ + "name": "with-jsx", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-jsx/public/favicon.ico b/examples/with-jsx/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-jsx/public/favicon.ico differ diff --git a/examples/with-jsx/src/App.vue b/examples/with-jsx/src/App.vue new file mode 100644 index 0000000..b7bd148 --- /dev/null +++ b/examples/with-jsx/src/App.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/examples/with-jsx/src/FooComp.jsx b/examples/with-jsx/src/FooComp.jsx new file mode 100644 index 0000000..c8d0e69 --- /dev/null +++ b/examples/with-jsx/src/FooComp.jsx @@ -0,0 +1,7 @@ +import { defineComponent } from "vue" + +export default defineComponent({ + setup() { + return () =>
Foo
+ }, +}) diff --git a/examples/with-jsx/src/assets/base.css b/examples/with-jsx/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-jsx/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-jsx/src/assets/logo.svg b/examples/with-jsx/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-jsx/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-jsx/src/assets/main.css b/examples/with-jsx/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-jsx/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-jsx/src/components/HelloWorld.vue b/examples/with-jsx/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-jsx/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-jsx/src/components/TheWelcome.vue b/examples/with-jsx/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-jsx/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-jsx/src/components/WelcomeItem.vue b/examples/with-jsx/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-jsx/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-jsx/src/components/icons/IconCommunity.vue b/examples/with-jsx/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-jsx/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx/src/components/icons/IconDocumentation.vue b/examples/with-jsx/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-jsx/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx/src/components/icons/IconEcosystem.vue b/examples/with-jsx/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-jsx/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx/src/components/icons/IconSupport.vue b/examples/with-jsx/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-jsx/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-jsx/src/components/icons/IconTooling.vue b/examples/with-jsx/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-jsx/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-jsx/src/main.ts b/examples/with-jsx/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-jsx/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-jsx/tsconfig.app.json b/examples/with-jsx/tsconfig.app.json new file mode 100644 index 0000000..5807729 --- /dev/null +++ b/examples/with-jsx/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "allowJs": true, + "checkJs": true + } +} diff --git a/examples/with-jsx/tsconfig.json b/examples/with-jsx/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/with-jsx/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/with-jsx/tsconfig.node.json b/examples/with-jsx/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-jsx/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-jsx/vite.config.ts b/examples/with-jsx/vite.config.ts new file mode 100644 index 0000000..36c6187 --- /dev/null +++ b/examples/with-jsx/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-nightwatch/.gitignore b/examples/with-nightwatch/.gitignore new file mode 100644 index 0000000..0b938f1 --- /dev/null +++ b/examples/with-nightwatch/.gitignore @@ -0,0 +1,33 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo + +logs/ +tests_output/ diff --git a/examples/with-nightwatch/.vscode/extensions.json b/examples/with-nightwatch/.vscode/extensions.json new file mode 100644 index 0000000..fdab373 --- /dev/null +++ b/examples/with-nightwatch/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "Vue.volar", + "browserstackcom.nightwatch", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-nightwatch/README.md b/examples/with-nightwatch/README.md new file mode 100644 index 0000000..96c91b4 --- /dev/null +++ b/examples/with-nightwatch/README.md @@ -0,0 +1,62 @@ +# with-nightwatch + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run End-to-End Tests with [Nightwatch](https://nightwatchjs.org/) + +```sh +# When using CI, the project must be built first. +npm run build + +# Runs the end-to-end tests +npm run test:e2e +# Runs the tests only on Chrome +npm run test:e2e -- --env chrome +# Runs the tests of a specific file +npm run test:e2e -- tests/e2e/example.ts +# Runs the tests in debug mode +npm run test:e2e -- --debug +``` + +### Run Headed Component Tests with [Nightwatch Component Testing](https://nightwatchjs.org/guide/component-testing/introduction.html) + +```sh +npm run test:unit +npm run test:unit -- --headless # for headless testing +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-nightwatch/env.d.ts b/examples/with-nightwatch/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-nightwatch/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-nightwatch/eslint.config.js b/examples/with-nightwatch/eslint.config.js new file mode 100644 index 0000000..627e180 --- /dev/null +++ b/examples/with-nightwatch/eslint.config.js @@ -0,0 +1,27 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, + + { + // nightwatch specs + files: ['tests/e2e/**/*.{js,ts}', '**/__tests__/**/*.{js,ts}'], + rules: { + 'no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + // You can use https://github.com/ihordiachenko/eslint-plugin-chai-friendly for more accurate linting + }, + }, +) diff --git a/examples/with-nightwatch/index.html b/examples/with-nightwatch/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-nightwatch/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-nightwatch/nightwatch.conf.cjs b/examples/with-nightwatch/nightwatch.conf.cjs new file mode 100644 index 0000000..542647e --- /dev/null +++ b/examples/with-nightwatch/nightwatch.conf.cjs @@ -0,0 +1,153 @@ +// +// Refer to the online docs for more details: +// https://nightwatchjs.org/guide/configuration/nightwatch-configuration-file.html +// +// _ _ _ _ _ _ _ +// | \ | |(_) | | | | | | | | +// | \| | _ __ _ | |__ | |_ __ __ __ _ | |_ ___ | |__ +// | . ` || | / _` || '_ \ | __|\ \ /\ / / / _` || __| / __|| '_ \ +// | |\ || || (_| || | | || |_ \ V V / | (_| || |_ | (__ | | | | +// \_| \_/|_| \__, ||_| |_| \__| \_/\_/ \__,_| \__| \___||_| |_| +// __/ | +// |___/ +// + +module.exports = { + // An array of folders (excluding subfolders) where your tests are located; + // if this is not specified, the test source must be passed as the second argument to the test runner. + src_folders: [], + + // See https://nightwatchjs.org/guide/concepts/page-object-model.html + page_objects_path: [], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-commands.html + custom_commands_path: [], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-assertions.html + custom_assertions_path: [], + + // See https://nightwatchjs.org/guide/extending-nightwatch/adding-plugins.html + plugins: ['@nightwatch/vue'], + + // See https://nightwatchjs.org/guide/concepts/test-globals.html#external-test-globals + globals_path: '', + + vite_dev_server: { + start_vite: true, + port: process.env.CI ? 4173 : 5173 + }, + + webdriver: {}, + + test_workers: { + enabled: true, + workers: 'auto' + }, + + test_settings: { + default: { + disable_error_log: false, + launch_url: `http://localhost:${process.env.CI ? '4173' : '5173'}`, + + screenshots: { + enabled: false, + path: 'screens', + on_failure: true + }, + + desiredCapabilities: { + browserName: 'firefox' + }, + + webdriver: { + start_process: true, + server_path: '' + } + }, + + safari: { + desiredCapabilities: { + browserName: 'safari', + alwaysMatch: { + acceptInsecureCerts: false + } + }, + webdriver: { + start_process: true, + server_path: '' + } + }, + + firefox: { + desiredCapabilities: { + browserName: 'firefox', + alwaysMatch: { + acceptInsecureCerts: true, + 'moz:firefoxOptions': { + args: [ + // '-headless', + // '-verbose' + ] + } + } + }, + webdriver: { + start_process: true, + server_path: '', + cli_args: [ + // very verbose geckodriver logs + // '-vv' + ] + } + }, + + chrome: { + desiredCapabilities: { + browserName: 'chrome', + 'goog:chromeOptions': { + // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/ + // + // w3c:false tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78) + w3c: true, + args: [ + //'--no-sandbox', + //'--ignore-certificate-errors', + //'--allow-insecure-localhost', + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + server_path: '', + cli_args: [ + // --verbose + ] + } + }, + + edge: { + desiredCapabilities: { + browserName: 'MicrosoftEdge', + 'ms:edgeOptions': { + w3c: true, + // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options + args: [ + //'--headless' + ] + } + }, + + webdriver: { + start_process: true, + // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ + // and set the location below: + server_path: '', + cli_args: [ + // --verbose + ] + } + } + } +} diff --git a/examples/with-nightwatch/nightwatch/index.html b/examples/with-nightwatch/nightwatch/index.html new file mode 100644 index 0000000..b7e1ec7 --- /dev/null +++ b/examples/with-nightwatch/nightwatch/index.html @@ -0,0 +1,16 @@ + + + + + + + + + Vue Renderer + + + +
+ + + diff --git a/examples/with-nightwatch/nightwatch/nightwatch.d.ts b/examples/with-nightwatch/nightwatch/nightwatch.d.ts new file mode 100644 index 0000000..1b16a9c --- /dev/null +++ b/examples/with-nightwatch/nightwatch/nightwatch.d.ts @@ -0,0 +1,14 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unused-vars */ +import { NightwatchCustomAssertions, NightwatchCustomCommands } from 'nightwatch' + +declare module 'nightwatch' { + interface NightwatchCustomAssertions { + // Add your custom assertions' types here + // elementHasCount: (selector: string, count: number) => NightwatchBrowser + } + + interface NightwatchCustomCommands { + // Add your custom commands' types here + // strictClick: (selector: string) => NightwatchBrowser + } +} diff --git a/examples/with-nightwatch/nightwatch/tsconfig.json b/examples/with-nightwatch/nightwatch/tsconfig.json new file mode 100644 index 0000000..8cd7ca1 --- /dev/null +++ b/examples/with-nightwatch/nightwatch/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "../node_modules/.tmp/tsconfig.nightwatch.tsbuildinfo", + + "target": "ESNext", + "module": "commonjs", + "moduleResolution": "node", + "rootDir": "../", + "lib": ["ESNext", "dom"], + "types": ["nightwatch"] + }, + "include": ["../node_modules/@nightwatch/**/*", "../src/components/**/*", "../tests/e2e/**/*"], + "ts-node": { + "transpileOnly": true + }, + "files": ["nightwatch.d.ts"] +} diff --git a/examples/with-nightwatch/package.json b/examples/with-nightwatch/package.json new file mode 100644 index 0000000..47192fc --- /dev/null +++ b/examples/with-nightwatch/package.json @@ -0,0 +1,39 @@ +{ + "name": "with-nightwatch", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:e2e": "nightwatch tests/e2e/*", + "test:unit": "nightwatch src/**/__tests__/*", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@nightwatch/vue": "^3.1.2", + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.7.0", + "chromedriver": "^134.0.5", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "geckodriver": "^5.0.0", + "nightwatch": "^3.12.1", + "npm-run-all2": "^7.0.2", + "ts-node": "^10.9.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vite-plugin-nightwatch": "^0.4.6", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-nightwatch/public/favicon.ico b/examples/with-nightwatch/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-nightwatch/public/favicon.ico differ diff --git a/examples/with-nightwatch/src/App.vue b/examples/with-nightwatch/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-nightwatch/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-nightwatch/src/assets/base.css b/examples/with-nightwatch/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-nightwatch/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-nightwatch/src/assets/logo.svg b/examples/with-nightwatch/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-nightwatch/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-nightwatch/src/assets/main.css b/examples/with-nightwatch/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-nightwatch/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-nightwatch/src/components/HelloWorld.vue b/examples/with-nightwatch/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-nightwatch/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-nightwatch/src/components/TheWelcome.vue b/examples/with-nightwatch/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-nightwatch/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-nightwatch/src/components/WelcomeItem.vue b/examples/with-nightwatch/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-nightwatch/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-nightwatch/src/components/__tests__/HelloWorld.spec.ts b/examples/with-nightwatch/src/components/__tests__/HelloWorld.spec.ts new file mode 100644 index 0000000..810641e --- /dev/null +++ b/examples/with-nightwatch/src/components/__tests__/HelloWorld.spec.ts @@ -0,0 +1,14 @@ +describe('Hello World', function () { + before((browser) => { + browser.init() + }) + + it('renders properly', async function () { + const welcomeComponent = await browser.mountComponent('/src/components/HelloWorld.vue', {props: {msg: 'Hello Nightwatch'}}); + + browser.expect.element(welcomeComponent).to.be.present; + browser.expect.element('h1').text.to.contain('Hello Nightwatch'); + }) + + after((browser) => browser.end()) +}) diff --git a/examples/with-nightwatch/src/components/icons/IconCommunity.vue b/examples/with-nightwatch/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-nightwatch/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-nightwatch/src/components/icons/IconDocumentation.vue b/examples/with-nightwatch/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-nightwatch/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-nightwatch/src/components/icons/IconEcosystem.vue b/examples/with-nightwatch/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-nightwatch/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-nightwatch/src/components/icons/IconSupport.vue b/examples/with-nightwatch/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-nightwatch/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-nightwatch/src/components/icons/IconTooling.vue b/examples/with-nightwatch/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-nightwatch/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-nightwatch/src/main.ts b/examples/with-nightwatch/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-nightwatch/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-nightwatch/tests/e2e/example.ts b/examples/with-nightwatch/tests/e2e/example.ts new file mode 100644 index 0000000..b8e003a --- /dev/null +++ b/examples/with-nightwatch/tests/e2e/example.ts @@ -0,0 +1,12 @@ +describe('My First Test', function () { + before((browser) => { + browser.init() + }) + + it('visits the app root url', function () { + browser.assert.textContains('.green', 'You did it!') + }) + + after((browser) => browser.end()) +}) + diff --git a/examples/with-nightwatch/tsconfig.app.json b/examples/with-nightwatch/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-nightwatch/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-nightwatch/tsconfig.json b/examples/with-nightwatch/tsconfig.json new file mode 100644 index 0000000..5c385ae --- /dev/null +++ b/examples/with-nightwatch/tsconfig.json @@ -0,0 +1,14 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./nightwatch/tsconfig.json" + } + ] +} diff --git a/examples/with-nightwatch/tsconfig.node.json b/examples/with-nightwatch/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-nightwatch/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-nightwatch/vite.config.ts b/examples/with-nightwatch/vite.config.ts new file mode 100644 index 0000000..fd83c5b --- /dev/null +++ b/examples/with-nightwatch/vite.config.ts @@ -0,0 +1,20 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import nightwatchPlugin from 'vite-plugin-nightwatch' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + nightwatchPlugin({ + renderPage: './nightwatch/index.html' + }), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-playwright/.gitignore b/examples/with-playwright/.gitignore new file mode 100644 index 0000000..aef72d0 --- /dev/null +++ b/examples/with-playwright/.gitignore @@ -0,0 +1,33 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo + +test-results/ +playwright-report/ diff --git a/examples/with-playwright/.vscode/extensions.json b/examples/with-playwright/.vscode/extensions.json new file mode 100644 index 0000000..a56bc4d --- /dev/null +++ b/examples/with-playwright/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "Vue.volar", + "ms-playwright.playwright", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-playwright/README.md b/examples/with-playwright/README.md new file mode 100644 index 0000000..940e16b --- /dev/null +++ b/examples/with-playwright/README.md @@ -0,0 +1,58 @@ +# with-playwright + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run End-to-End Tests with [Playwright](https://playwright.dev) + +```sh +# Install browsers for the first run +npx playwright install + +# When testing on CI, must build the project first +npm run build + +# Runs the end-to-end tests +npm run test:e2e +# Runs the tests only on Chromium +npm run test:e2e -- --project=chromium +# Runs the tests of a specific file +npm run test:e2e -- tests/example.spec.ts +# Runs the tests in debug mode +npm run test:e2e -- --debug +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-playwright/e2e/tsconfig.json b/examples/with-playwright/e2e/tsconfig.json new file mode 100644 index 0000000..be3bbfc --- /dev/null +++ b/examples/with-playwright/e2e/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": ["./**/*"] +} diff --git a/examples/with-playwright/e2e/vue.spec.ts b/examples/with-playwright/e2e/vue.spec.ts new file mode 100644 index 0000000..3e5a3d0 --- /dev/null +++ b/examples/with-playwright/e2e/vue.spec.ts @@ -0,0 +1,8 @@ +import { test, expect } from '@playwright/test'; + +// See here how to get started: +// https://playwright.dev/docs/intro +test('visits the app root url', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('div.greetings > h1')).toHaveText('You did it!'); +}) diff --git a/examples/with-playwright/env.d.ts b/examples/with-playwright/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-playwright/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-playwright/eslint.config.js b/examples/with-playwright/eslint.config.js new file mode 100644 index 0000000..f9b59eb --- /dev/null +++ b/examples/with-playwright/eslint.config.js @@ -0,0 +1,23 @@ +import pluginVue from 'eslint-plugin-vue' +import pluginPlaywright from 'eslint-plugin-playwright' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, + + { + ...pluginPlaywright.configs['flat/recommended'], + files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], + }, +) diff --git a/examples/with-playwright/index.html b/examples/with-playwright/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-playwright/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-playwright/package.json b/examples/with-playwright/package.json new file mode 100644 index 0000000..daf418e --- /dev/null +++ b/examples/with-playwright/package.json @@ -0,0 +1,33 @@ +{ + "name": "with-playwright", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:e2e": "playwright test", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@playwright/test": "^1.51.1", + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-playwright": "^2.2.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-playwright/playwright.config.ts b/examples/with-playwright/playwright.config.ts new file mode 100644 index 0000000..92075cc --- /dev/null +++ b/examples/with-playwright/playwright.config.ts @@ -0,0 +1,110 @@ +import process from 'node:process' +import { defineConfig, devices } from '@playwright/test' + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000 + }, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: 'http://localhost:5173', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + + /* Only on CI systems run the tests headless */ + headless: !!process.env.CI + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'] + } + }, + { + name: 'firefox', + use: { + ...devices['Desktop Firefox'] + } + }, + { + name: 'webkit', + use: { + ...devices['Desktop Safari'] + } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + webServer: { + /** + * Use the dev server by default for faster feedback loop. + * Use the preview server on CI for more realistic testing. + * Playwright will re-use the local server if there is already a dev-server running. + */ + command: process.env.CI ? 'vite preview --port 5173' : 'vite dev', + port: 5173, + reuseExistingServer: !process.env.CI + } +}) diff --git a/examples/with-playwright/public/favicon.ico b/examples/with-playwright/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-playwright/public/favicon.ico differ diff --git a/examples/with-playwright/src/App.vue b/examples/with-playwright/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-playwright/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-playwright/src/assets/base.css b/examples/with-playwright/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-playwright/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-playwright/src/assets/logo.svg b/examples/with-playwright/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-playwright/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-playwright/src/assets/main.css b/examples/with-playwright/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-playwright/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-playwright/src/components/HelloWorld.vue b/examples/with-playwright/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-playwright/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-playwright/src/components/TheWelcome.vue b/examples/with-playwright/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-playwright/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-playwright/src/components/WelcomeItem.vue b/examples/with-playwright/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-playwright/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-playwright/src/components/icons/IconCommunity.vue b/examples/with-playwright/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-playwright/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-playwright/src/components/icons/IconDocumentation.vue b/examples/with-playwright/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-playwright/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-playwright/src/components/icons/IconEcosystem.vue b/examples/with-playwright/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-playwright/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-playwright/src/components/icons/IconSupport.vue b/examples/with-playwright/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-playwright/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-playwright/src/components/icons/IconTooling.vue b/examples/with-playwright/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-playwright/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-playwright/src/main.ts b/examples/with-playwright/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-playwright/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-playwright/tsconfig.app.json b/examples/with-playwright/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-playwright/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-playwright/tsconfig.json b/examples/with-playwright/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/with-playwright/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/with-playwright/tsconfig.node.json b/examples/with-playwright/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-playwright/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-playwright/vite.config.ts b/examples/with-playwright/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/with-playwright/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-prettier/.gitignore b/examples/with-prettier/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-prettier/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-prettier/.prettierrc.json b/examples/with-prettier/.prettierrc.json new file mode 100644 index 0000000..66e2335 --- /dev/null +++ b/examples/with-prettier/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "semi": false, + "tabWidth": 2, + "singleQuote": true, + "printWidth": 100, + "trailingComma": "none" +} \ No newline at end of file diff --git a/examples/with-prettier/.vscode/extensions.json b/examples/with-prettier/.vscode/extensions.json new file mode 100644 index 0000000..93ea3e7 --- /dev/null +++ b/examples/with-prettier/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] +} diff --git a/examples/with-prettier/README.md b/examples/with-prettier/README.md new file mode 100644 index 0000000..3f50446 --- /dev/null +++ b/examples/with-prettier/README.md @@ -0,0 +1,39 @@ +# with-prettier + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-prettier/env.d.ts b/examples/with-prettier/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-prettier/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-prettier/eslint.config.js b/examples/with-prettier/eslint.config.js new file mode 100644 index 0000000..800ac48 --- /dev/null +++ b/examples/with-prettier/eslint.config.js @@ -0,0 +1,20 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, + + skipFormatting +) diff --git a/examples/with-prettier/index.html b/examples/with-prettier/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-prettier/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-prettier/package.json b/examples/with-prettier/package.json new file mode 100644 index 0000000..3698d8b --- /dev/null +++ b/examples/with-prettier/package.json @@ -0,0 +1,33 @@ +{ + "name": "with-prettier", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix", + "format": "prettier --write src/" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-prettier": "^10.2.0", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "prettier": "3.5.3", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-prettier/public/favicon.ico b/examples/with-prettier/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-prettier/public/favicon.ico differ diff --git a/examples/with-prettier/src/App.vue b/examples/with-prettier/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-prettier/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-prettier/src/assets/base.css b/examples/with-prettier/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-prettier/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-prettier/src/assets/logo.svg b/examples/with-prettier/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-prettier/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-prettier/src/assets/main.css b/examples/with-prettier/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-prettier/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-prettier/src/components/HelloWorld.vue b/examples/with-prettier/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-prettier/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-prettier/src/components/TheWelcome.vue b/examples/with-prettier/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-prettier/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-prettier/src/components/WelcomeItem.vue b/examples/with-prettier/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-prettier/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-prettier/src/components/icons/IconCommunity.vue b/examples/with-prettier/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-prettier/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-prettier/src/components/icons/IconDocumentation.vue b/examples/with-prettier/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-prettier/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-prettier/src/components/icons/IconEcosystem.vue b/examples/with-prettier/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-prettier/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-prettier/src/components/icons/IconSupport.vue b/examples/with-prettier/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-prettier/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-prettier/src/components/icons/IconTooling.vue b/examples/with-prettier/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-prettier/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-prettier/src/main.ts b/examples/with-prettier/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-prettier/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-prettier/tsconfig.app.json b/examples/with-prettier/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-prettier/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-prettier/tsconfig.json b/examples/with-prettier/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/with-prettier/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/with-prettier/tsconfig.node.json b/examples/with-prettier/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-prettier/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-prettier/vite.config.ts b/examples/with-prettier/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/with-prettier/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-tsx-in-vue/.gitignore b/examples/with-tsx-in-vue/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-tsx-in-vue/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-tsx-in-vue/.vscode/extensions.json b/examples/with-tsx-in-vue/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/with-tsx-in-vue/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-tsx-in-vue/README.md b/examples/with-tsx-in-vue/README.md new file mode 100644 index 0000000..ab22cf9 --- /dev/null +++ b/examples/with-tsx-in-vue/README.md @@ -0,0 +1,39 @@ +# with-tsx-in-vue + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-tsx-in-vue/env.d.ts b/examples/with-tsx-in-vue/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-tsx-in-vue/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-tsx-in-vue/eslint.config.js b/examples/with-tsx-in-vue/eslint.config.js new file mode 100644 index 0000000..570ddca --- /dev/null +++ b/examples/with-tsx-in-vue/eslint.config.js @@ -0,0 +1,23 @@ +import pluginVue from 'eslint-plugin-vue' +import { + defineConfigWithVueTs, + vueTsConfigs, + configureVueProject, +} from '@vue/eslint-config-typescript' + +configureVueProject({ scriptLangs: ['ts', 'tsx'] }) + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/examples/with-tsx-in-vue/index.html b/examples/with-tsx-in-vue/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-tsx-in-vue/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-tsx-in-vue/package.json b/examples/with-tsx-in-vue/package.json new file mode 100644 index 0000000..a71b18d --- /dev/null +++ b/examples/with-tsx-in-vue/package.json @@ -0,0 +1,31 @@ +{ + "name": "with-tsx-in-vue", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-tsx-in-vue/public/favicon.ico b/examples/with-tsx-in-vue/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-tsx-in-vue/public/favicon.ico differ diff --git a/examples/with-tsx-in-vue/src/App.vue b/examples/with-tsx-in-vue/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-tsx-in-vue/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-tsx-in-vue/src/assets/base.css b/examples/with-tsx-in-vue/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-tsx-in-vue/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-tsx-in-vue/src/assets/logo.svg b/examples/with-tsx-in-vue/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-tsx-in-vue/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-tsx-in-vue/src/assets/main.css b/examples/with-tsx-in-vue/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-tsx-in-vue/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-tsx-in-vue/src/components/HelloWorld.vue b/examples/with-tsx-in-vue/src/components/HelloWorld.vue new file mode 100644 index 0000000..d582316 --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/HelloWorld.vue @@ -0,0 +1,50 @@ + + + diff --git a/examples/with-tsx-in-vue/src/components/TheWelcome.vue b/examples/with-tsx-in-vue/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-tsx-in-vue/src/components/WelcomeItem.vue b/examples/with-tsx-in-vue/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-tsx-in-vue/src/components/icons/IconCommunity.vue b/examples/with-tsx-in-vue/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx-in-vue/src/components/icons/IconDocumentation.vue b/examples/with-tsx-in-vue/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx-in-vue/src/components/icons/IconEcosystem.vue b/examples/with-tsx-in-vue/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx-in-vue/src/components/icons/IconSupport.vue b/examples/with-tsx-in-vue/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx-in-vue/src/components/icons/IconTooling.vue b/examples/with-tsx-in-vue/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-tsx-in-vue/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-tsx-in-vue/src/main.ts b/examples/with-tsx-in-vue/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-tsx-in-vue/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-tsx-in-vue/tsconfig.app.json b/examples/with-tsx-in-vue/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-tsx-in-vue/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-tsx-in-vue/tsconfig.json b/examples/with-tsx-in-vue/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/with-tsx-in-vue/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/with-tsx-in-vue/tsconfig.node.json b/examples/with-tsx-in-vue/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-tsx-in-vue/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-tsx-in-vue/vite.config.ts b/examples/with-tsx-in-vue/vite.config.ts new file mode 100644 index 0000000..36c6187 --- /dev/null +++ b/examples/with-tsx-in-vue/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-tsx/.gitignore b/examples/with-tsx/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-tsx/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-tsx/.vscode/extensions.json b/examples/with-tsx/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/with-tsx/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-tsx/README.md b/examples/with-tsx/README.md new file mode 100644 index 0000000..fb2c08e --- /dev/null +++ b/examples/with-tsx/README.md @@ -0,0 +1,39 @@ +# with-tsx + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-tsx/env.d.ts b/examples/with-tsx/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-tsx/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-tsx/eslint.config.js b/examples/with-tsx/eslint.config.js new file mode 100644 index 0000000..22a6176 --- /dev/null +++ b/examples/with-tsx/eslint.config.js @@ -0,0 +1,17 @@ +import pluginVue from 'eslint-plugin-vue' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/examples/with-tsx/index.html b/examples/with-tsx/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-tsx/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-tsx/package.json b/examples/with-tsx/package.json new file mode 100644 index 0000000..1221c48 --- /dev/null +++ b/examples/with-tsx/package.json @@ -0,0 +1,31 @@ +{ + "name": "with-tsx", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitejs/plugin-vue-jsx": "^4.1.2", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-tsx/public/favicon.ico b/examples/with-tsx/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-tsx/public/favicon.ico differ diff --git a/examples/with-tsx/src/App.vue b/examples/with-tsx/src/App.vue new file mode 100644 index 0000000..b7bd148 --- /dev/null +++ b/examples/with-tsx/src/App.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/examples/with-tsx/src/FooComp.tsx b/examples/with-tsx/src/FooComp.tsx new file mode 100644 index 0000000..c8d0e69 --- /dev/null +++ b/examples/with-tsx/src/FooComp.tsx @@ -0,0 +1,7 @@ +import { defineComponent } from "vue" + +export default defineComponent({ + setup() { + return () =>
Foo
+ }, +}) diff --git a/examples/with-tsx/src/assets/base.css b/examples/with-tsx/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-tsx/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-tsx/src/assets/logo.svg b/examples/with-tsx/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-tsx/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-tsx/src/assets/main.css b/examples/with-tsx/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-tsx/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-tsx/src/components/HelloWorld.vue b/examples/with-tsx/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-tsx/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-tsx/src/components/TheWelcome.vue b/examples/with-tsx/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-tsx/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-tsx/src/components/WelcomeItem.vue b/examples/with-tsx/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-tsx/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-tsx/src/components/icons/IconCommunity.vue b/examples/with-tsx/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-tsx/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx/src/components/icons/IconDocumentation.vue b/examples/with-tsx/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-tsx/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx/src/components/icons/IconEcosystem.vue b/examples/with-tsx/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-tsx/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx/src/components/icons/IconSupport.vue b/examples/with-tsx/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-tsx/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-tsx/src/components/icons/IconTooling.vue b/examples/with-tsx/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-tsx/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-tsx/src/main.ts b/examples/with-tsx/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-tsx/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-tsx/tsconfig.app.json b/examples/with-tsx/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-tsx/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-tsx/tsconfig.json b/examples/with-tsx/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/examples/with-tsx/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/examples/with-tsx/tsconfig.node.json b/examples/with-tsx/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-tsx/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-tsx/vite.config.ts b/examples/with-tsx/vite.config.ts new file mode 100644 index 0000000..36c6187 --- /dev/null +++ b/examples/with-tsx/vite.config.ts @@ -0,0 +1,18 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-vitest/.gitignore b/examples/with-vitest/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/examples/with-vitest/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/examples/with-vitest/.vscode/extensions.json b/examples/with-vitest/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/examples/with-vitest/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/examples/with-vitest/README.md b/examples/with-vitest/README.md new file mode 100644 index 0000000..477fc86 --- /dev/null +++ b/examples/with-vitest/README.md @@ -0,0 +1,45 @@ +# with-vitest + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Run Unit Tests with [Vitest](https://vitest.dev/) + +```sh +npm run test:unit +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/examples/with-vitest/env.d.ts b/examples/with-vitest/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/with-vitest/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/with-vitest/eslint.config.js b/examples/with-vitest/eslint.config.js new file mode 100644 index 0000000..90710a3 --- /dev/null +++ b/examples/with-vitest/eslint.config.js @@ -0,0 +1,23 @@ +import pluginVue from 'eslint-plugin-vue' +import pluginVitest from '@vitest/eslint-plugin' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, + + { + ...pluginVitest.configs['recommended'], + files: ['src/**/__tests__/*'], + }, +) diff --git a/examples/with-vitest/index.html b/examples/with-vitest/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/examples/with-vitest/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json new file mode 100644 index 0000000..fe3bff4 --- /dev/null +++ b/examples/with-vitest/package.json @@ -0,0 +1,36 @@ +{ + "name": "with-vitest", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:unit": "vitest", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/jsdom": "^21.1.7", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vitest/eslint-plugin": "^1.1.38", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "jsdom": "^26.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vitest": "^3.1.1", + "vue-tsc": "^2.2.8" + } +} diff --git a/examples/with-vitest/public/favicon.ico b/examples/with-vitest/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/examples/with-vitest/public/favicon.ico differ diff --git a/examples/with-vitest/src/App.vue b/examples/with-vitest/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/examples/with-vitest/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/with-vitest/src/assets/base.css b/examples/with-vitest/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/examples/with-vitest/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/examples/with-vitest/src/assets/logo.svg b/examples/with-vitest/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/examples/with-vitest/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/examples/with-vitest/src/assets/main.css b/examples/with-vitest/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/examples/with-vitest/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/examples/with-vitest/src/components/HelloWorld.vue b/examples/with-vitest/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/examples/with-vitest/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/examples/with-vitest/src/components/TheWelcome.vue b/examples/with-vitest/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/examples/with-vitest/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/examples/with-vitest/src/components/WelcomeItem.vue b/examples/with-vitest/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/examples/with-vitest/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/examples/with-vitest/src/components/__tests__/HelloWorld.spec.ts b/examples/with-vitest/src/components/__tests__/HelloWorld.spec.ts new file mode 100644 index 0000000..2533202 --- /dev/null +++ b/examples/with-vitest/src/components/__tests__/HelloWorld.spec.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest' + +import { mount } from '@vue/test-utils' +import HelloWorld from '../HelloWorld.vue' + +describe('HelloWorld', () => { + it('renders properly', () => { + const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) + expect(wrapper.text()).toContain('Hello Vitest') + }) +}) diff --git a/examples/with-vitest/src/components/icons/IconCommunity.vue b/examples/with-vitest/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/examples/with-vitest/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-vitest/src/components/icons/IconDocumentation.vue b/examples/with-vitest/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/examples/with-vitest/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-vitest/src/components/icons/IconEcosystem.vue b/examples/with-vitest/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/examples/with-vitest/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-vitest/src/components/icons/IconSupport.vue b/examples/with-vitest/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/examples/with-vitest/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/examples/with-vitest/src/components/icons/IconTooling.vue b/examples/with-vitest/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/examples/with-vitest/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/examples/with-vitest/src/main.ts b/examples/with-vitest/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/examples/with-vitest/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/examples/with-vitest/tsconfig.app.json b/examples/with-vitest/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/examples/with-vitest/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/with-vitest/tsconfig.json b/examples/with-vitest/tsconfig.json new file mode 100644 index 0000000..100cf6a --- /dev/null +++ b/examples/with-vitest/tsconfig.json @@ -0,0 +1,14 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ] +} diff --git a/examples/with-vitest/tsconfig.node.json b/examples/with-vitest/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/examples/with-vitest/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/examples/with-vitest/tsconfig.vitest.json b/examples/with-vitest/tsconfig.vitest.json new file mode 100644 index 0000000..571995d --- /dev/null +++ b/examples/with-vitest/tsconfig.vitest.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.app.json", + "exclude": [], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo", + + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/examples/with-vitest/vite.config.ts b/examples/with-vitest/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/examples/with-vitest/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/examples/with-vitest/vitest.config.ts b/examples/with-vitest/vitest.config.ts new file mode 100644 index 0000000..4b1c897 --- /dev/null +++ b/examples/with-vitest/vitest.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url' +import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' +import viteConfig from './vite.config' + +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + environment: 'jsdom', + exclude: [...configDefaults.exclude, 'e2e/**'], + root: fileURLToPath(new URL('./', import.meta.url)) + } + }) +) diff --git a/index.js b/index.js deleted file mode 100644 index 9d1ef63..0000000 --- a/index.js +++ /dev/null @@ -1,46 +0,0 @@ -module.exports = { - plugins: ['@typescript-eslint'], - - // Prerequisite `eslint-plugin-vue`, being extended, sets - // root property `parser` to `'vue-eslint-parser'`, which, for code parsing, - // in turn delegates to the parser, specified in `parserOptions.parser`: - // https://github.com/vuejs/eslint-plugin-vue#what-is-the-use-the-latest-vue-eslint-parser-error - parserOptions: { - parser: { - 'js': 'espree', - 'jsx': 'espree', - 'cjs': 'espree', - 'mjs': 'espree', - - 'ts': require.resolve('@typescript-eslint/parser'), - 'tsx': require.resolve('@typescript-eslint/parser'), - 'cts': require.resolve('@typescript-eslint/parser'), - 'mts': require.resolve('@typescript-eslint/parser'), - - // Leave the template parser unspecified, so that it could be determined by ` diff --git a/test/fixtures/allow-js/main.js b/test/fixtures/allow-js/main.js deleted file mode 100644 index 0f15bf2..0000000 --- a/test/fixtures/allow-js/main.js +++ /dev/null @@ -1,2 +0,0 @@ -let a = b + 1 -export default a diff --git a/test/fixtures/allow-js/tsconfig.json b/test/fixtures/allow-js/tsconfig.json deleted file mode 100644 index c18c242..0000000 --- a/test/fixtures/allow-js/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.vue" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/test/fixtures/default/src/App.vue b/test/fixtures/default/src/App.vue deleted file mode 100644 index 00ffdcc..0000000 --- a/test/fixtures/default/src/App.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/test/fixtures/default/src/HelloWorld.tsx b/test/fixtures/default/src/HelloWorld.tsx deleted file mode 100644 index a9e5451..0000000 --- a/test/fixtures/default/src/HelloWorld.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, Prop, Vue } from 'vue-property-decorator'; - -@Component -export default class HelloWorld extends Vue { - @Prop() private msg!: string; - - render(): JSX.Element { - return ( -
-

{ this.msg }

-
- ) - } -} diff --git a/test/fixtures/default/src/main.ts b/test/fixtures/default/src/main.ts deleted file mode 100644 index 98c0085..0000000 --- a/test/fixtures/default/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import Vue from 'vue' -import App from '@/App.vue' - -Vue.config.productionTip = false - -new Vue({ - render: h => h(App), -}).$mount('#app') diff --git a/test/fixtures/default/src/shims-tsx.d.ts b/test/fixtures/default/src/shims-tsx.d.ts deleted file mode 100644 index a175b0d..0000000 --- a/test/fixtures/default/src/shims-tsx.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Vue, { VNode } from 'vue' - -declare global { - namespace JSX { - // tslint:disable no-empty-interface - interface Element extends VNode {} - // tslint:disable no-empty-interface - interface ElementClass extends Vue {} - interface IntrinsicElements { - [elem: string]: any; - } - } -} diff --git a/test/fixtures/default/src/shims-vue.d.ts b/test/fixtures/default/src/shims-vue.d.ts deleted file mode 100644 index d9f24fa..0000000 --- a/test/fixtures/default/src/shims-vue.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module '*.vue' { - import Vue from 'vue' - export default Vue -} diff --git a/test/fixtures/default/tsconfig.json b/test/fixtures/default/tsconfig.json deleted file mode 100644 index 60a1f00..0000000 --- a/test/fixtures/default/tsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "paths": { - "@/*": [ - "src/*" - ] - }, - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "src/**/*.ts", - "src/**/*.tsx", - "src/**/*.vue" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/test/fixtures/file-based-routing/.editorconfig b/test/fixtures/file-based-routing/.editorconfig new file mode 100644 index 0000000..ecea360 --- /dev/null +++ b/test/fixtures/file-based-routing/.editorconfig @@ -0,0 +1,6 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/test/fixtures/file-based-routing/.gitignore b/test/fixtures/file-based-routing/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/test/fixtures/file-based-routing/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/test/fixtures/file-based-routing/.vscode/extensions.json b/test/fixtures/file-based-routing/.vscode/extensions.json new file mode 100644 index 0000000..5efa012 --- /dev/null +++ b/test/fixtures/file-based-routing/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint", + "EditorConfig.EditorConfig" + ] +} diff --git a/test/fixtures/file-based-routing/README.md b/test/fixtures/file-based-routing/README.md new file mode 100644 index 0000000..13fd6eb --- /dev/null +++ b/test/fixtures/file-based-routing/README.md @@ -0,0 +1,39 @@ +# file-based-routing + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/test/fixtures/file-based-routing/env.d.ts b/test/fixtures/file-based-routing/env.d.ts new file mode 100644 index 0000000..dabd0de --- /dev/null +++ b/test/fixtures/file-based-routing/env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/test/fixtures/file-based-routing/eslint.config.js b/test/fixtures/file-based-routing/eslint.config.js new file mode 100644 index 0000000..fe2854c --- /dev/null +++ b/test/fixtures/file-based-routing/eslint.config.js @@ -0,0 +1,26 @@ +import pluginVue from 'eslint-plugin-vue' +import { + defineConfigWithVueTs, + vueTsConfigs, +} from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommendedTypeChecked, + + { + rules: { + 'vue/multi-word-component-names': 'off', + }, + }, +) diff --git a/test/fixtures/file-based-routing/index.html b/test/fixtures/file-based-routing/index.html new file mode 100644 index 0000000..9e5fc8f --- /dev/null +++ b/test/fixtures/file-based-routing/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/test/fixtures/file-based-routing/package.json b/test/fixtures/file-based-routing/package.json new file mode 100644 index 0000000..c1978b1 --- /dev/null +++ b/test/fixtures/file-based-routing/package.json @@ -0,0 +1,33 @@ +{ + "name": "file-based-routing", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13", + "vue-router": "^4.5.0" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.1", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "unplugin-vue-router": "^0.12.0", + "vite": "^6.2.0", + "vite-plugin-vue-devtools": "^7.7.2", + "vue-tsc": "^2.2.8" + } +} diff --git a/test/fixtures/file-based-routing/public/favicon.ico b/test/fixtures/file-based-routing/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/test/fixtures/file-based-routing/public/favicon.ico differ diff --git a/test/fixtures/file-based-routing/src/App.vue b/test/fixtures/file-based-routing/src/App.vue new file mode 100644 index 0000000..7905b05 --- /dev/null +++ b/test/fixtures/file-based-routing/src/App.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/test/fixtures/file-based-routing/src/assets/base.css b/test/fixtures/file-based-routing/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/test/fixtures/file-based-routing/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/test/fixtures/file-based-routing/src/assets/logo.svg b/test/fixtures/file-based-routing/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/test/fixtures/file-based-routing/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/test/fixtures/file-based-routing/src/assets/main.css b/test/fixtures/file-based-routing/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/test/fixtures/file-based-routing/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/test/fixtures/file-based-routing/src/components/HelloWorld.vue b/test/fixtures/file-based-routing/src/components/HelloWorld.vue new file mode 100644 index 0000000..d174cf8 --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/test/fixtures/file-based-routing/src/components/TheWelcome.vue b/test/fixtures/file-based-routing/src/components/TheWelcome.vue new file mode 100644 index 0000000..3d4eecd --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/TheWelcome.vue @@ -0,0 +1,90 @@ + + + diff --git a/test/fixtures/file-based-routing/src/components/WelcomeItem.vue b/test/fixtures/file-based-routing/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/test/fixtures/file-based-routing/src/components/icons/IconCommunity.vue b/test/fixtures/file-based-routing/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/file-based-routing/src/components/icons/IconDocumentation.vue b/test/fixtures/file-based-routing/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/file-based-routing/src/components/icons/IconEcosystem.vue b/test/fixtures/file-based-routing/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/file-based-routing/src/components/icons/IconSupport.vue b/test/fixtures/file-based-routing/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/file-based-routing/src/components/icons/IconTooling.vue b/test/fixtures/file-based-routing/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/test/fixtures/file-based-routing/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/test/fixtures/file-based-routing/src/main.ts b/test/fixtures/file-based-routing/src/main.ts new file mode 100644 index 0000000..5a5dbdb --- /dev/null +++ b/test/fixtures/file-based-routing/src/main.ts @@ -0,0 +1,11 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' +import router from './router' + +const app = createApp(App) + +app.use(router) + +app.mount('#app') diff --git a/test/fixtures/file-based-routing/src/pages/[...path].vue b/test/fixtures/file-based-routing/src/pages/[...path].vue new file mode 100644 index 0000000..18b3051 --- /dev/null +++ b/test/fixtures/file-based-routing/src/pages/[...path].vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/file-based-routing/src/pages/about.vue b/test/fixtures/file-based-routing/src/pages/about.vue new file mode 100644 index 0000000..756ad2a --- /dev/null +++ b/test/fixtures/file-based-routing/src/pages/about.vue @@ -0,0 +1,15 @@ + + + diff --git a/test/fixtures/file-based-routing/src/pages/index.vue b/test/fixtures/file-based-routing/src/pages/index.vue new file mode 100644 index 0000000..d5c0217 --- /dev/null +++ b/test/fixtures/file-based-routing/src/pages/index.vue @@ -0,0 +1,9 @@ + + + diff --git a/test/fixtures/file-based-routing/src/pages/users/[id].vue b/test/fixtures/file-based-routing/src/pages/users/[id].vue new file mode 100644 index 0000000..6976eb9 --- /dev/null +++ b/test/fixtures/file-based-routing/src/pages/users/[id].vue @@ -0,0 +1,6 @@ + diff --git a/test/fixtures/file-based-routing/src/router/index.ts b/test/fixtures/file-based-routing/src/router/index.ts new file mode 100644 index 0000000..42597a4 --- /dev/null +++ b/test/fixtures/file-based-routing/src/router/index.ts @@ -0,0 +1,13 @@ +import { createRouter, createWebHistory } from 'vue-router' +import { routes, handleHotUpdate } from 'vue-router/auto-routes' + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes, +}) + +export default router + +if (import.meta.hot) { + handleHotUpdate(router) +} diff --git a/test/fixtures/file-based-routing/tsconfig.app.json b/test/fixtures/file-based-routing/tsconfig.app.json new file mode 100644 index 0000000..bb1b2ec --- /dev/null +++ b/test/fixtures/file-based-routing/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "typed-router.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/test/fixtures/file-based-routing/tsconfig.json b/test/fixtures/file-based-routing/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/test/fixtures/file-based-routing/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/test/fixtures/file-based-routing/tsconfig.node.json b/test/fixtures/file-based-routing/tsconfig.node.json new file mode 100644 index 0000000..5a0c6a5 --- /dev/null +++ b/test/fixtures/file-based-routing/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/test/fixtures/file-based-routing/typed-router.d.ts b/test/fixtures/file-based-routing/typed-router.d.ts new file mode 100644 index 0000000..ef336ad --- /dev/null +++ b/test/fixtures/file-based-routing/typed-router.d.ts @@ -0,0 +1,26 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️ +// It's recommended to commit this file. +// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry. + +declare module 'vue-router/auto-routes' { + import type { + RouteRecordInfo, + ParamValue, + ParamValueOneOrMore, + ParamValueZeroOrMore, + ParamValueZeroOrOne, + } from 'vue-router' + + /** + * Route name map generated by unplugin-vue-router + */ + export interface RouteNamedMap { + '/': RouteRecordInfo<'/', '/', Record, Record>, + '/[...path]': RouteRecordInfo<'/[...path]', '/:path(.*)', { path: ParamValue }, { path: ParamValue }>, + '/about': RouteRecordInfo<'/about', '/about', Record, Record>, + '/users/[id]': RouteRecordInfo<'/users/[id]', '/users/:id', { id: ParamValue }, { id: ParamValue }>, + } +} diff --git a/test/fixtures/file-based-routing/vite.config.ts b/test/fixtures/file-based-routing/vite.config.ts new file mode 100644 index 0000000..afbeec4 --- /dev/null +++ b/test/fixtures/file-based-routing/vite.config.ts @@ -0,0 +1,20 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' +import vueRouter from 'unplugin-vue-router/vite' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vueRouter(), + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + }, + }, +}) diff --git a/test/fixtures/sfc/App.vue b/test/fixtures/sfc/App.vue deleted file mode 100644 index 7fb9b86..0000000 --- a/test/fixtures/sfc/App.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - - - diff --git a/test/fixtures/sfc/tsconfig.json b/test/fixtures/sfc/tsconfig.json deleted file mode 100644 index c18c242..0000000 --- a/test/fixtures/sfc/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.vue" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/test/fixtures/ts/main.ts b/test/fixtures/ts/main.ts deleted file mode 100644 index fa0ebf3..0000000 --- a/test/fixtures/ts/main.ts +++ /dev/null @@ -1 +0,0 @@ -interface Foo {} diff --git a/test/fixtures/ts/tsconfig.json b/test/fixtures/ts/tsconfig.json deleted file mode 100644 index c18c242..0000000 --- a/test/fixtures/ts/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.vue" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/test/fixtures/tsx-in-sfc/App.vue b/test/fixtures/tsx-in-sfc/App.vue deleted file mode 100644 index 748b984..0000000 --- a/test/fixtures/tsx-in-sfc/App.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/test/fixtures/tsx-in-sfc/shims-tsx.d.ts b/test/fixtures/tsx-in-sfc/shims-tsx.d.ts deleted file mode 100644 index a175b0d..0000000 --- a/test/fixtures/tsx-in-sfc/shims-tsx.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Vue, { VNode } from 'vue' - -declare global { - namespace JSX { - // tslint:disable no-empty-interface - interface Element extends VNode {} - // tslint:disable no-empty-interface - interface ElementClass extends Vue {} - interface IntrinsicElements { - [elem: string]: any; - } - } -} diff --git a/test/fixtures/tsx-in-sfc/shims-vue.d.ts b/test/fixtures/tsx-in-sfc/shims-vue.d.ts deleted file mode 100644 index d9f24fa..0000000 --- a/test/fixtures/tsx-in-sfc/shims-vue.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module '*.vue' { - import Vue from 'vue' - export default Vue -} diff --git a/test/fixtures/tsx-in-sfc/tsconfig.json b/test/fixtures/tsx-in-sfc/tsconfig.json deleted file mode 100644 index c18c242..0000000 --- a/test/fixtures/tsx-in-sfc/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.vue" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/test/fixtures/tsx/main.tsx b/test/fixtures/tsx/main.tsx deleted file mode 100644 index c7d2c5e..0000000 --- a/test/fixtures/tsx/main.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, Prop, Vue } from 'vue-property-decorator'; - -@Component -export default class HelloWorld extends Vue { - @Prop() private msg!: string; - - render() { - return ( -
-

{ this.msg }

-
- ) - } -} - -interface Foo {} diff --git a/test/fixtures/tsx/shims-tsx.d.ts b/test/fixtures/tsx/shims-tsx.d.ts deleted file mode 100644 index a175b0d..0000000 --- a/test/fixtures/tsx/shims-tsx.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Vue, { VNode } from 'vue' - -declare global { - namespace JSX { - // tslint:disable no-empty-interface - interface Element extends VNode {} - // tslint:disable no-empty-interface - interface ElementClass extends Vue {} - interface IntrinsicElements { - [elem: string]: any; - } - } -} diff --git a/test/fixtures/tsx/shims-vue.d.ts b/test/fixtures/tsx/shims-vue.d.ts deleted file mode 100644 index d9f24fa..0000000 --- a/test/fixtures/tsx/shims-vue.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module '*.vue' { - import Vue from 'vue' - export default Vue -} diff --git a/test/fixtures/tsx/tsconfig.json b/test/fixtures/tsx/tsconfig.json deleted file mode 100644 index c18c242..0000000 --- a/test/fixtures/tsx/tsconfig.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "target": "esnext", - "module": "esnext", - "strict": true, - "jsx": "preserve", - "importHelpers": true, - "moduleResolution": "node", - "experimentalDecorators": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "baseUrl": ".", - "lib": [ - "esnext", - "dom", - "dom.iterable", - "scripthost" - ] - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.vue" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/test/fixtures/with-older-espree/.gitignore b/test/fixtures/with-older-espree/.gitignore new file mode 100644 index 0000000..8ee54e8 --- /dev/null +++ b/test/fixtures/with-older-espree/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/test/fixtures/with-older-espree/.vscode/extensions.json b/test/fixtures/with-older-espree/.vscode/extensions.json new file mode 100644 index 0000000..64db0b2 --- /dev/null +++ b/test/fixtures/with-older-espree/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "Vue.volar", + "dbaeumer.vscode-eslint" + ] +} diff --git a/test/fixtures/with-older-espree/README.md b/test/fixtures/with-older-espree/README.md new file mode 100644 index 0000000..e28f5cc --- /dev/null +++ b/test/fixtures/with-older-espree/README.md @@ -0,0 +1,39 @@ +with-older-espree# minimal + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/test/fixtures/with-older-espree/env.d.ts b/test/fixtures/with-older-espree/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/test/fixtures/with-older-espree/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/test/fixtures/with-older-espree/eslint.config.js b/test/fixtures/with-older-espree/eslint.config.js new file mode 100644 index 0000000..9dea2cd --- /dev/null +++ b/test/fixtures/with-older-espree/eslint.config.js @@ -0,0 +1,20 @@ +import pluginVue from 'eslint-plugin-vue' +import { + defineConfigWithVueTs, + vueTsConfigs, +} from '@vue/eslint-config-typescript' + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, +) diff --git a/test/fixtures/with-older-espree/index.html b/test/fixtures/with-older-espree/index.html new file mode 100644 index 0000000..a888544 --- /dev/null +++ b/test/fixtures/with-older-espree/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/test/fixtures/with-older-espree/package.json b/test/fixtures/with-older-espree/package.json new file mode 100644 index 0000000..20e4ec7 --- /dev/null +++ b/test/fixtures/with-older-espree/package.json @@ -0,0 +1,31 @@ +{ + "name": "with-older-espree", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build --force", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.5", + "@types/node": "^22.13.15", + "@vitejs/plugin-vue": "^5.2.3", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.23.0", + "eslint-plugin-vue": "~10.0.0", + "espree": "^9.6.1", + "npm-run-all2": "^7.0.2", + "typescript": "~5.8.2", + "vite": "^6.2.0", + "vue-tsc": "^2.2.8" + } +} diff --git a/test/fixtures/with-older-espree/public/favicon.ico b/test/fixtures/with-older-espree/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/test/fixtures/with-older-espree/public/favicon.ico differ diff --git a/test/fixtures/with-older-espree/src/App.vue b/test/fixtures/with-older-espree/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/test/fixtures/with-older-espree/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/test/fixtures/with-older-espree/src/assets/base.css b/test/fixtures/with-older-espree/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/test/fixtures/with-older-espree/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/test/fixtures/with-older-espree/src/assets/logo.svg b/test/fixtures/with-older-espree/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/test/fixtures/with-older-espree/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/test/fixtures/with-older-espree/src/assets/main.css b/test/fixtures/with-older-espree/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/test/fixtures/with-older-espree/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/test/fixtures/with-older-espree/src/components/HelloWorld.vue b/test/fixtures/with-older-espree/src/components/HelloWorld.vue new file mode 100644 index 0000000..e1a721c --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/test/fixtures/with-older-espree/src/components/TheWelcome.vue b/test/fixtures/with-older-espree/src/components/TheWelcome.vue new file mode 100644 index 0000000..49d8f73 --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/TheWelcome.vue @@ -0,0 +1,88 @@ + + + diff --git a/test/fixtures/with-older-espree/src/components/WelcomeItem.vue b/test/fixtures/with-older-espree/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/test/fixtures/with-older-espree/src/components/icons/IconCommunity.vue b/test/fixtures/with-older-espree/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/with-older-espree/src/components/icons/IconDocumentation.vue b/test/fixtures/with-older-espree/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/with-older-espree/src/components/icons/IconEcosystem.vue b/test/fixtures/with-older-espree/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/with-older-espree/src/components/icons/IconSupport.vue b/test/fixtures/with-older-espree/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/test/fixtures/with-older-espree/src/components/icons/IconTooling.vue b/test/fixtures/with-older-espree/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/test/fixtures/with-older-espree/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/test/fixtures/with-older-espree/src/main.ts b/test/fixtures/with-older-espree/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/test/fixtures/with-older-espree/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/test/fixtures/with-older-espree/tsconfig.app.json b/test/fixtures/with-older-espree/tsconfig.app.json new file mode 100644 index 0000000..e14c754 --- /dev/null +++ b/test/fixtures/with-older-espree/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/test/fixtures/with-older-espree/tsconfig.json b/test/fixtures/with-older-espree/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/test/fixtures/with-older-espree/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/test/fixtures/with-older-espree/tsconfig.node.json b/test/fixtures/with-older-espree/tsconfig.node.json new file mode 100644 index 0000000..f094063 --- /dev/null +++ b/test/fixtures/with-older-espree/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node20/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*" + ], + "compilerOptions": { + "composite": true, + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/test/fixtures/with-older-espree/vite.config.ts b/test/fixtures/with-older-espree/vite.config.ts new file mode 100644 index 0000000..5c45e1d --- /dev/null +++ b/test/fixtures/with-older-espree/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + } +}) diff --git a/test/index.spec.js b/test/index.spec.js deleted file mode 100644 index 8bd35fa..0000000 --- a/test/index.spec.js +++ /dev/null @@ -1,61 +0,0 @@ -const path = require('path') -const execa = require('execa') - -const eslintPath = path.resolve(__dirname, '../node_modules/.bin/eslint') - -async function lintProject (name) { - const projectPath = path.resolve(__dirname, 'fixtures', name) - - try { - return await execa( - eslintPath, - [ - `${projectPath}/`, - '--ext', - '.vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts', - '--no-ignore' - ], - { - cwd: projectPath, - } - ) - } catch (e) { - return e - } -} - -test('a default project should pass lint', async () => { - const { stdout } = await lintProject('default') - expect(stdout).toEqual('') -}) - -test('should lint .ts file', async () => { - const { stdout } = await lintProject('ts') - expect(stdout).toMatch('@typescript-eslint/no-unused-vars') -}) - -test('should lint .vue file', async () => { - const { stdout } = await lintProject('sfc') - expect(stdout).toMatch('@typescript-eslint/no-unused-vars') -}) - -test('should lint .tsx', async () => { - const { stdout } = await lintProject('tsx') - expect(stdout).not.toMatch('Parsing error') - expect(stdout).toMatch('@typescript-eslint/no-unused-vars') -}) - -test('should lint tsx block in .vue file', async () => { - const { stdout } = await lintProject('tsx-in-sfc') - expect(stdout).not.toMatch('Parsing error') - expect(stdout).toMatch('@typescript-eslint/no-unused-vars') -}) - -test('should not override eslint:recommended rules for normal js files', async () => { - const { stdout } = await lintProject('allow-js') - // errors in .vue file - expect(stdout).toMatch('no-const-assign') - - // errors in .js file - expect(stdout).toMatch('no-undef') -}) diff --git a/test/index.spec.ts b/test/index.spec.ts new file mode 100644 index 0000000..83d8eb9 --- /dev/null +++ b/test/index.spec.ts @@ -0,0 +1,237 @@ +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +import { describe, test, expect } from 'vitest' +import { execa } from 'execa' + +const WHITESPACE_ONLY = /^\s*$/ + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +const FROM_EXAMPLES = 'FROM_EXAMPLES' +const FROM_FIXTURES = 'FROM_FIXTURES' +type ProjectType = 'FROM_EXAMPLES' | 'FROM_FIXTURES' + +function runLintAgainst(projectName: string, projectType: ProjectType = FROM_EXAMPLES) { + const parentDir = path.join(__dirname, projectType === FROM_EXAMPLES ? '../examples' : './fixtures') + const projectDir = path.join(parentDir, projectName) + // Use `pnpm` to avoid locating each `eslint` bin ourselves. + // Use `--silent` to only print the output of the command, stripping the pnpm log. + return execa({ + preferLocal: true, + cwd: projectDir, + reject: false, + })`pnpm --silent lint` +} + +function setupFileMutations(filename: string) { + // Read the file + const fileContents = fs.readFileSync(filename, 'utf8') + + // Implementation for modifying and restoring the file + function modify(getNewContents: (oldContents: string) => string) { + fs.writeFileSync(filename, getNewContents(fileContents)) + } + + function restore() { + fs.writeFileSync(filename, fileContents) + } + + return { modify, restore } +} + +describe('should pass lint without error in new projects', () => { + for (const projectName of [ + 'minimal', + 'allow-js', + 'with-tsx', + 'with-tsx-in-vue', + 'with-jsx', + 'with-jsx-in-vue', + 'with-prettier', + 'with-cypress', + 'with-nightwatch', + 'with-playwright', + 'with-vitest', + 'type-checked', + 'disable-ts-in-templates', + 'api-before-14.3', + 'custom-type-checked-rules-on-and-off', + ]) { + test(projectName, async () => { + const { stdout } = await runLintAgainst(projectName) + expect(stdout).toMatch(WHITESPACE_ONLY) + }) + } +}) + +describe('should report error on recommended rule violations in .vue files', () => { + function appendBannedTsCommentToVueScript(oldContents: string) { + return oldContents.replace('', '// @ts-ignore\n') + } + for (const projectName of [ + 'minimal', + 'allow-js', + 'with-tsx', + 'with-tsx-in-vue', + 'with-jsx', + 'with-jsx-in-vue', + 'with-prettier', + 'with-cypress', + 'with-nightwatch', + 'with-playwright', + 'with-vitest', + 'type-checked', + 'disable-ts-in-templates', + 'api-before-14.3', + 'custom-type-checked-rules-on-and-off', + ]) { + test(`src/App.vue in ${projectName}`, async () => { + const appVuePath = path.join( + __dirname, + '../examples', + projectName, + 'src/App.vue', + ) + + const { modify, restore } = setupFileMutations(appVuePath) + modify(appendBannedTsCommentToVueScript) + const { failed, stdout } = await runLintAgainst(projectName) + restore() + + expect(failed).toBe(true) + expect(stdout).toContain('App.vue') + expect(stdout).toContain('@typescript-eslint/ban-ts-comment') + }) + } +}) + +describe('should report error on recommended rule violations in other script files', () => { + function appendBannedTsComment(oldContents: string) { + return oldContents + '\n// @ts-ignore\n' + } + + for (const projectName of [ + 'minimal', + 'allow-js', + 'with-tsx', + 'with-tsx-in-vue', + 'with-jsx', + 'with-jsx-in-vue', + 'with-prettier', + 'with-cypress', + 'with-nightwatch', + 'with-playwright', + 'with-vitest', + 'type-checked', + 'disable-ts-in-templates', + 'api-before-14.3', + ]) { + test(`main.ts in ${projectName}`, async () => { + const mainTsPath = path.join( + __dirname, + '../examples', + projectName, + 'src/main.ts', + ) + + const { modify, restore } = setupFileMutations(mainTsPath) + modify(appendBannedTsComment) + const { failed, stdout } = await runLintAgainst(projectName) + restore() + + expect(failed).toBe(true) + expect(stdout).toContain('main.ts') + expect(stdout).toContain(' @typescript-eslint/ban-ts-comment') + }) + } + + function appendThisAlias(oldContents: string) { + return ( + oldContents + + ` +class Example { + method() { + const that = this; + console.log(that.method) + } +} +new Example() +` + ) + } + + test('.js in allow-js', async () => { + const jsPath = path.join(__dirname, '../examples/allow-js/src/foo.js') + const { modify, restore } = setupFileMutations(jsPath) + modify(appendThisAlias) + const { failed, stdout } = await runLintAgainst('allow-js') + restore() + + expect(failed).toBe(true) + expect(stdout).toContain('@typescript-eslint/no-this-alias') + }) + test('.tsx in with-tsx', async () => { + const tsxPath = path.join(__dirname, '../examples/with-tsx/src/FooComp.tsx') + const { modify, restore } = setupFileMutations(tsxPath) + modify(appendThisAlias) + const { failed, stdout } = await runLintAgainst('with-tsx') + restore() + + expect(failed).toBe(true) + expect(stdout).toContain('@typescript-eslint/no-this-alias') + }) + test('.jsx in with-jsx', async () => { + const jsxPath = path.join(__dirname, '../examples/with-jsx/src/FooComp.jsx') + const { modify, restore } = setupFileMutations(jsxPath) + modify(appendThisAlias) + const { failed, stdout } = await runLintAgainst('with-jsx') + restore() + + expect(failed).toBe(true) + expect(stdout).toContain('@typescript-eslint/no-this-alias') + }) +}) + +test('#87: should not error if the project root has an older version of espree installed', async () => { + const { stdout } = await runLintAgainst('with-older-espree', FROM_FIXTURES) + expect(stdout).toMatch(WHITESPACE_ONLY) +}) + +test('#102: should set configs correctly for paths with glob-like syntax (e.g. file-based-routing patterns)', async () => { + const { stdout } = await runLintAgainst('file-based-routing', FROM_FIXTURES) + expect(stdout).toMatch(WHITESPACE_ONLY) +}) + +test('(API before 14.3) should guide user to use camelCase names in "extends"', async () => { + const eslintConfigPath = path.join(__dirname, '../examples/api-before-14.3/eslint.config.js') + const { modify, restore } = setupFileMutations(eslintConfigPath) + modify((oldContents) => oldContents.replace('recommendedTypeChecked', 'recommended-type-checked')) + const { failed, stderr } = await runLintAgainst('api-before-14.3') + restore() + + expect(failed).toBe(true) + expect(stderr).contain('Please use "recommendedTypeChecked"') +}) + +test('should allow users to turn on/off type-aware rules by just targeting `**/*.vue` files', async () => { + const appVuePath = path.join(__dirname, '../examples/custom-type-checked-rules-on-and-off/src/App.vue') + const { modify, restore } = setupFileMutations(appVuePath) + modify((oldContents) => oldContents.replace('', ` +// Should not cause lint error +export type UnionUnknown = unknown | 'foo'; + +const array: number[] = []; +// Should cause lint error +array.sort(); +`)) + + const { failed, stdout } = await runLintAgainst('custom-type-checked-rules-on-and-off') + restore() + + expect(failed).toBe(true) + expect(stdout).not.toContain('no-redundant-type-constituents') + expect(stdout).toContain('require-array-sort-compare') +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..38e958a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,30 @@ +{ + "include": ["src"], + "extends": "@tsconfig/node20/tsconfig.json", + "compilerOptions": { + // Treat files as modules even if it doesn't use import/export + "moduleDetection": "force", + + // Ignore module structure + "module": "Preserve", + "moduleResolution": "Bundler", + + // Allow JSON modules to be imported + "resolveJsonModule": true, + + // Allow JS files to be imported from TS and vice versa + "allowJs": true, + "checkJs": true, + + // Use correct ESM import behavior + "esModuleInterop": true, + + // Disallow features that require cross-file awareness + "isolatedModules": true, + + "verbatimModuleSyntax": true, + + "lib": ["ES2020", "ES2023.Array"], + "types": ["node"] + }, +}