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/.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..a81a712 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,120 @@ # @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*` configuraion 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. - -### `@vue/eslint-config-typescript` +## Usage -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. +Because of the complexity of this config, it is exported as a factory function that takes an options object and returns an ESLint configuration object. -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 vueTsEslintConfig from "@vue/eslint-config-typescript"; + +export default [ + ...pluginVue.configs["flat/essential"], + ...vueTsEslintConfig(), +] ``` -### `@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..ec5fc7b --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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/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..cc82d86 --- /dev/null +++ b/examples/minimal/eslint.config.js @@ -0,0 +1,13 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), +] 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..2eaad04 --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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/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..9addd11 --- /dev/null +++ b/examples/with-cypress/eslint.config.js @@ -0,0 +1,23 @@ +import pluginVue from 'eslint-plugin-vue' +import pluginCypress from 'eslint-plugin-cypress/flat' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), + + { + files: [ + '**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}', + 'cypress/support/**/*.{js,ts,jsx,tsx}' + ], + ...pluginCypress.configs.recommended, + } +] 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..cb4a5c7 --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "cypress": "^13.14.2", + "eslint": "^9.10.0", + "eslint-plugin-cypress": "^3.5.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "start-server-and-test": "^2.0.8", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..b41e3d7 --- /dev/null +++ b/examples/with-jsx-in-vue/eslint.config.js @@ -0,0 +1,20 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.js', '**/*.mjs', '**/*.jsx', '**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig({ + supportedScriptLangs: { + ts: true, + tsx: true, + js: true, + jsx: true + } + }), +] 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..10cb939 --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vitejs/plugin-vue-jsx": "^4.0.1", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..3717306 --- /dev/null +++ b/examples/with-jsx/eslint.config.js @@ -0,0 +1,13 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.js', '**/*.mjs', '**/*.jsx', '**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), +] 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..7e264ce --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vitejs/plugin-vue-jsx": "^4.0.1", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..b72b971 --- /dev/null +++ b/examples/with-nightwatch/eslint.config.js @@ -0,0 +1,22 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), + + { + 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..44ae1ea --- /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.6" + }, + "devDependencies": { + "@nightwatch/vue": "^3.1.1", + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.5.1", + "chromedriver": "^129.0.0", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "geckodriver": "^4.4.4", + "nightwatch": "^3.8.0", + "npm-run-all2": "^6.2.3", + "ts-node": "^10.9.2", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vite-plugin-nightwatch": "^0.4.6", + "vue-tsc": "^2.1.6" + } +} 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..ea1bf58 --- /dev/null +++ b/examples/with-playwright/eslint.config.js @@ -0,0 +1,19 @@ +import pluginVue from 'eslint-plugin-vue' +import pluginPlaywright from 'eslint-plugin-playwright' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), + + { + ...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..c25e18d --- /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.6" + }, + "devDependencies": { + "@playwright/test": "^1.47.1", + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-playwright": "^1.6.2", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..4f95aa5 --- /dev/null +++ b/examples/with-prettier/eslint.config.js @@ -0,0 +1,16 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), + + 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..34e957b --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-prettier": "^10.0.0-rc.2", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "prettier": "^3.3.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..07a622c --- /dev/null +++ b/examples/with-tsx-in-vue/eslint.config.js @@ -0,0 +1,18 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig({ + supportedScriptLangs: { + ts: true, + tsx: true + } + }), +] 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..f491bca --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vitejs/plugin-vue-jsx": "^4.0.1", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..c216239 --- /dev/null +++ b/examples/with-tsx/eslint.config.js @@ -0,0 +1,13 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.tsx', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), +] 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..d93f226 --- /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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vitejs/plugin-vue-jsx": "^4.0.1", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vue-tsc": "^2.1.6" + } +} 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..cc82d86 --- /dev/null +++ b/examples/with-vitest/eslint.config.js @@ -0,0 +1,13 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.ts', '**/*.mts', '**/*.vue'], + ignores: ['**/dist/**'], + }, + + ...pluginVue.configs['flat/essential'], + ...vueTsEslintConfig(), +] 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..0ac7b86 --- /dev/null +++ b/examples/with-vitest/package.json @@ -0,0 +1,35 @@ +{ + "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.6" + }, + "devDependencies": { + "@tsconfig/node20": "^20.1.4", + "@types/jsdom": "^21.1.7", + "@types/node": "^20.16.5", + "@vitejs/plugin-vue": "^5.1.4", + "@vue/eslint-config-typescript": "workspace:*", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.5.1", + "eslint": "^9.10.0", + "eslint-plugin-vue": "^9.28.0", + "jsdom": "^25.0.0", + "npm-run-all2": "^6.2.3", + "typescript": "~5.5.4", + "vite": "^5.4.6", + "vitest": "^1.6.0", + "vue-tsc": "^2.1.6" + } +} 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/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/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..6525d9d --- /dev/null +++ b/test/index.spec.ts @@ -0,0 +1,180 @@ +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) + +function runLintAgainst(projectName: string) { + const projectDir = path.join(__dirname, '../examples', 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', + ]) { + 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', + ]) { + 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', + ]) { + 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') + }) +}) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b4c2fb5 --- /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"], + "types": ["node"] + }, +}