diff --git a/examples/with-vite/.eslintrc.js b/examples/with-vite/.eslintrc.js
new file mode 100644
index 0000000000000..c8df607506ccb
--- /dev/null
+++ b/examples/with-vite/.eslintrc.js
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: ["custom"],
+};
diff --git a/examples/with-vite/.gitignore b/examples/with-vite/.gitignore
new file mode 100644
index 0000000000000..a627497ca20da
--- /dev/null
+++ b/examples/with-vite/.gitignore
@@ -0,0 +1,11 @@
+.DS_Store
+node_modules
+.turbo
+*.log
+dist
+dist-ssr
+*.local
+.env
+.cache
+server/dist
+public/dist
diff --git a/examples/with-vite/README.md b/examples/with-vite/README.md
new file mode 100644
index 0000000000000..627e5bfa5128b
--- /dev/null
+++ b/examples/with-vite/README.md
@@ -0,0 +1,26 @@
+# `Turborepo` Vite starter
+
+This is an official starter Turborepo.
+
+## What's inside?
+
+This Turborepo includes the following packages and apps:
+
+### Apps and Packages
+
+- `docs`: a vanilla [vite](https://vitejs.dev) ts app
+- `web`: another vanilla [vite](https://vitejs.dev) ts app
+- `ui`: a stub component & utility library shared by both `web` and `docs` applications
+- `eslint-config-custom`: shared `eslint` configurations
+- `tsconfig`: `tsconfig.json`s used throughout the monorepo
+
+Each package and app is 100% [TypeScript](https://www.typescriptlang.org/).
+
+### Utilities
+
+This Turborepo has some additional tools already setup for you:
+
+- [TypeScript](https://www.typescriptlang.org/) for static type checking
+- [ESLint](https://eslint.org/) for code linting
+- [Jest](https://jestjs.io) test runner for all things JavaScript
+- [Prettier](https://prettier.io) for code formatting
diff --git a/examples/with-vite/apps/docs/.eslintrc.cjs b/examples/with-vite/apps/docs/.eslintrc.cjs
new file mode 100644
index 0000000000000..c8df607506ccb
--- /dev/null
+++ b/examples/with-vite/apps/docs/.eslintrc.cjs
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: ["custom"],
+};
diff --git a/examples/with-vite/apps/docs/favicon.svg b/examples/with-vite/apps/docs/favicon.svg
new file mode 100644
index 0000000000000..de4aeddc12bdf
--- /dev/null
+++ b/examples/with-vite/apps/docs/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/examples/with-vite/apps/docs/index.html b/examples/with-vite/apps/docs/index.html
new file mode 100644
index 0000000000000..f86e483c942e8
--- /dev/null
+++ b/examples/with-vite/apps/docs/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + TS
+
+
+
+
+
+
diff --git a/examples/with-vite/apps/docs/package.json b/examples/with-vite/apps/docs/package.json
new file mode 100644
index 0000000000000..66bd24e34e00f
--- /dev/null
+++ b/examples/with-vite/apps/docs/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "docs",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
+ "lint": "eslint src/**/*.ts"
+ },
+ "dependencies": {
+ "ui": "*"
+ },
+ "devDependencies": {
+ "eslint": "^7.32.0",
+ "eslint-config-custom": "*",
+ "tsconfig": "*",
+ "typescript": "^4.6.4",
+ "vite": "^3.0.0"
+ }
+}
diff --git a/examples/with-vite/apps/docs/public/vite.svg b/examples/with-vite/apps/docs/public/vite.svg
new file mode 100644
index 0000000000000..e7b8dfb1b2a60
--- /dev/null
+++ b/examples/with-vite/apps/docs/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/with-vite/apps/docs/src/main.ts b/examples/with-vite/apps/docs/src/main.ts
new file mode 100644
index 0000000000000..85103f5b6fb75
--- /dev/null
+++ b/examples/with-vite/apps/docs/src/main.ts
@@ -0,0 +1,20 @@
+import "./style.css";
+import typescriptLogo from "./typescript.svg";
+import { Header, Counter, setupCounter } from "ui";
+
+document.querySelector("#app")!.innerHTML = `
+
+
+
+
+
+
+
+ ${Header({ title: "Docs" })}
+
+ ${Counter()}
+
+
+`;
+
+setupCounter(document.querySelector("#counter")!);
diff --git a/examples/with-vite/apps/docs/src/style.css b/examples/with-vite/apps/docs/src/style.css
new file mode 100644
index 0000000000000..12320801d3635
--- /dev/null
+++ b/examples/with-vite/apps/docs/src/style.css
@@ -0,0 +1,97 @@
+:root {
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 24px;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.vanilla:hover {
+ filter: drop-shadow(0 0 2em #f7df1eaa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/examples/with-vite/apps/docs/src/typescript.svg b/examples/with-vite/apps/docs/src/typescript.svg
new file mode 100644
index 0000000000000..d91c910cc30bf
--- /dev/null
+++ b/examples/with-vite/apps/docs/src/typescript.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/with-vite/apps/docs/src/vite-env.d.ts b/examples/with-vite/apps/docs/src/vite-env.d.ts
new file mode 100644
index 0000000000000..11f02fe2a0061
--- /dev/null
+++ b/examples/with-vite/apps/docs/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/with-vite/apps/docs/tsconfig.json b/examples/with-vite/apps/docs/tsconfig.json
new file mode 100644
index 0000000000000..a803037ccfec3
--- /dev/null
+++ b/examples/with-vite/apps/docs/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "extends": "tsconfig/vite.json",
+ "include": ["src"]
+}
diff --git a/examples/with-vite/apps/web/.eslintrc.cjs b/examples/with-vite/apps/web/.eslintrc.cjs
new file mode 100644
index 0000000000000..c8df607506ccb
--- /dev/null
+++ b/examples/with-vite/apps/web/.eslintrc.cjs
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: ["custom"],
+};
diff --git a/examples/with-vite/apps/web/favicon.svg b/examples/with-vite/apps/web/favicon.svg
new file mode 100644
index 0000000000000..de4aeddc12bdf
--- /dev/null
+++ b/examples/with-vite/apps/web/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/examples/with-vite/apps/web/index.html b/examples/with-vite/apps/web/index.html
new file mode 100644
index 0000000000000..f86e483c942e8
--- /dev/null
+++ b/examples/with-vite/apps/web/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + TS
+
+
+
+
+
+
diff --git a/examples/with-vite/apps/web/package.json b/examples/with-vite/apps/web/package.json
new file mode 100644
index 0000000000000..5405920adf064
--- /dev/null
+++ b/examples/with-vite/apps/web/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "web",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
+ "lint": "eslint src/**/*.ts"
+ },
+ "dependencies": {
+ "ui": "*"
+ },
+ "devDependencies": {
+ "eslint": "^7.32.0",
+ "eslint-config-custom": "*",
+ "tsconfig": "*",
+ "typescript": "^4.6.4",
+ "vite": "^3.0.0"
+ }
+}
diff --git a/examples/with-vite/apps/web/public/vite.svg b/examples/with-vite/apps/web/public/vite.svg
new file mode 100644
index 0000000000000..e7b8dfb1b2a60
--- /dev/null
+++ b/examples/with-vite/apps/web/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/with-vite/apps/web/src/main.ts b/examples/with-vite/apps/web/src/main.ts
new file mode 100644
index 0000000000000..2c1045b00a97f
--- /dev/null
+++ b/examples/with-vite/apps/web/src/main.ts
@@ -0,0 +1,20 @@
+import "./style.css";
+import typescriptLogo from "./typescript.svg";
+import { Header, Counter, setupCounter } from "ui";
+
+document.querySelector("#app")!.innerHTML = `
+
+
+
+
+
+
+
+ ${Header({ title: "Web" })}
+
+ ${Counter()}
+
+
+`;
+
+setupCounter(document.querySelector("#counter")!);
diff --git a/examples/with-vite/apps/web/src/style.css b/examples/with-vite/apps/web/src/style.css
new file mode 100644
index 0000000000000..12320801d3635
--- /dev/null
+++ b/examples/with-vite/apps/web/src/style.css
@@ -0,0 +1,97 @@
+:root {
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ line-height: 24px;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 320px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+#app {
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #646cffaa);
+}
+.logo.vanilla:hover {
+ filter: drop-shadow(0 0 2em #f7df1eaa);
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/examples/with-vite/apps/web/src/typescript.svg b/examples/with-vite/apps/web/src/typescript.svg
new file mode 100644
index 0000000000000..d91c910cc30bf
--- /dev/null
+++ b/examples/with-vite/apps/web/src/typescript.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/with-vite/apps/web/src/vite-env.d.ts b/examples/with-vite/apps/web/src/vite-env.d.ts
new file mode 100644
index 0000000000000..11f02fe2a0061
--- /dev/null
+++ b/examples/with-vite/apps/web/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/with-vite/apps/web/tsconfig.json b/examples/with-vite/apps/web/tsconfig.json
new file mode 100644
index 0000000000000..a803037ccfec3
--- /dev/null
+++ b/examples/with-vite/apps/web/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "extends": "tsconfig/vite.json",
+ "include": ["src"]
+}
diff --git a/examples/with-vite/package.json b/examples/with-vite/package.json
new file mode 100644
index 0000000000000..9ec2879b24ce2
--- /dev/null
+++ b/examples/with-vite/package.json
@@ -0,0 +1,19 @@
+{
+ "private": true,
+ "workspaces": [
+ "apps/*",
+ "packages/*"
+ ],
+ "scripts": {
+ "build": "turbo run build",
+ "dev": "turbo run dev --parallel",
+ "lint": "turbo run lint",
+ "format": "prettier --write \"**/*.{ts,tsx,md}\""
+ },
+ "devDependencies": {
+ "eslint": "^7.32.0",
+ "eslint-config-custom": "*",
+ "prettier": "^2.5.1",
+ "turbo": "latest"
+ }
+}
diff --git a/examples/with-vite/packages/eslint-config-custom/index.js b/examples/with-vite/packages/eslint-config-custom/index.js
new file mode 100644
index 0000000000000..9417d1c205c71
--- /dev/null
+++ b/examples/with-vite/packages/eslint-config-custom/index.js
@@ -0,0 +1,19 @@
+module.exports = {
+ env: {
+ node: true,
+ },
+ parser: "@typescript-eslint/parser",
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "prettier",
+ ],
+ plugins: ["@typescript-eslint"],
+ parserOptions: {
+ sourceType: "module",
+ ecmaVersion: 2020,
+ },
+ rules: {
+ "@typescript-eslint/no-non-null-assertion": "off",
+ },
+};
diff --git a/examples/with-vite/packages/eslint-config-custom/package.json b/examples/with-vite/packages/eslint-config-custom/package.json
new file mode 100644
index 0000000000000..39c63ddfa6ccd
--- /dev/null
+++ b/examples/with-vite/packages/eslint-config-custom/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "eslint-config-custom",
+ "version": "0.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "^5.30.7",
+ "@typescript-eslint/parser": "^5.30.7",
+ "eslint-config-prettier": "^8.5.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/examples/with-vite/packages/tsconfig/base.json b/examples/with-vite/packages/tsconfig/base.json
new file mode 100644
index 0000000000000..d72a9f3a27835
--- /dev/null
+++ b/examples/with-vite/packages/tsconfig/base.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "display": "Default",
+ "compilerOptions": {
+ "composite": false,
+ "declaration": true,
+ "declarationMap": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "inlineSources": false,
+ "isolatedModules": true,
+ "moduleResolution": "node",
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "preserveWatchOutput": true,
+ "skipLibCheck": true,
+ "strict": true
+ },
+ "exclude": ["node_modules"]
+}
diff --git a/examples/with-vite/packages/tsconfig/package.json b/examples/with-vite/packages/tsconfig/package.json
new file mode 100644
index 0000000000000..63d682a3242f5
--- /dev/null
+++ b/examples/with-vite/packages/tsconfig/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "tsconfig",
+ "version": "0.0.0",
+ "private": true,
+ "main": "index.js"
+}
diff --git a/examples/with-vite/packages/tsconfig/vite.json b/examples/with-vite/packages/tsconfig/vite.json
new file mode 100644
index 0000000000000..f8475363d5ef0
--- /dev/null
+++ b/examples/with-vite/packages/tsconfig/vite.json
@@ -0,0 +1,16 @@
+{
+ "extends": "tsconfig/base.json",
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "lib": ["ESNext", "DOM"],
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "noEmit": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noImplicitReturns": true
+ },
+ "exclude": ["node_modules"]
+}
diff --git a/examples/with-vite/packages/ui/.eslintrc.cjs b/examples/with-vite/packages/ui/.eslintrc.cjs
new file mode 100644
index 0000000000000..c8df607506ccb
--- /dev/null
+++ b/examples/with-vite/packages/ui/.eslintrc.cjs
@@ -0,0 +1,4 @@
+module.exports = {
+ root: true,
+ extends: ["custom"],
+};
diff --git a/examples/with-vite/packages/ui/components/counter.ts b/examples/with-vite/packages/ui/components/counter.ts
new file mode 100644
index 0000000000000..d58f8831cd36c
--- /dev/null
+++ b/examples/with-vite/packages/ui/components/counter.ts
@@ -0,0 +1,3 @@
+export function Counter() {
+ return ``;
+}
diff --git a/examples/with-vite/packages/ui/components/header.ts b/examples/with-vite/packages/ui/components/header.ts
new file mode 100644
index 0000000000000..14e0ab965c749
--- /dev/null
+++ b/examples/with-vite/packages/ui/components/header.ts
@@ -0,0 +1,7 @@
+export function Header({ title }: { title: string }) {
+ return `
+
+ `;
+}
diff --git a/examples/with-vite/packages/ui/index.ts b/examples/with-vite/packages/ui/index.ts
new file mode 100644
index 0000000000000..438ff065b2e15
--- /dev/null
+++ b/examples/with-vite/packages/ui/index.ts
@@ -0,0 +1,6 @@
+// utils
+export { setupCounter } from "./utils/counter";
+
+// components
+export { Header } from "./components/header";
+export { Counter } from "./components/counter";
diff --git a/examples/with-vite/packages/ui/package.json b/examples/with-vite/packages/ui/package.json
new file mode 100644
index 0000000000000..492f101577962
--- /dev/null
+++ b/examples/with-vite/packages/ui/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "ui",
+ "version": "0.0.0",
+ "main": "./index.ts",
+ "types": "./index.ts",
+ "license": "MIT",
+ "scripts": {
+ "lint": "eslint components/*.ts utils/*.ts"
+ },
+ "devDependencies": {
+ "eslint": "^7.32.0",
+ "eslint-config-custom": "*",
+ "tsconfig": "*",
+ "typescript": "^4.5.2"
+ }
+}
diff --git a/examples/with-vite/packages/ui/tsconfig.json b/examples/with-vite/packages/ui/tsconfig.json
new file mode 100644
index 0000000000000..61a00fa282757
--- /dev/null
+++ b/examples/with-vite/packages/ui/tsconfig.json
@@ -0,0 +1,5 @@
+{
+ "extends": "tsconfig/base.json",
+ "include": ["."],
+ "exclude": ["node_modules"]
+}
diff --git a/examples/with-vite/packages/ui/utils/counter.ts b/examples/with-vite/packages/ui/utils/counter.ts
new file mode 100644
index 0000000000000..0de7dcf5099b2
--- /dev/null
+++ b/examples/with-vite/packages/ui/utils/counter.ts
@@ -0,0 +1,9 @@
+export function setupCounter(element: HTMLButtonElement) {
+ let counter = 0;
+ const setCounter = (count: number) => {
+ counter = count;
+ element.innerText = `count is ${counter}`;
+ };
+ element.addEventListener("click", () => setCounter(++counter));
+ setCounter(0);
+}
diff --git a/examples/with-vite/turbo.json b/examples/with-vite/turbo.json
new file mode 100644
index 0000000000000..c1543e3b16973
--- /dev/null
+++ b/examples/with-vite/turbo.json
@@ -0,0 +1,14 @@
+{
+ "pipeline": {
+ "build": {
+ "dependsOn": ["^build"],
+ "outputs": ["dist/**"]
+ },
+ "lint": {
+ "outputs": []
+ },
+ "dev": {
+ "cache": false
+ }
+ }
+}