Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/example1/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.next
dist
5 changes: 5 additions & 0 deletions examples/example1/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-alert": "error"
}
}
169 changes: 169 additions & 0 deletions examples/example1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Vite+ example repo

This example has `apps/spa` and `apps/next`, both depend on `packages/logger`.

## Config

- Workspaces are self-contained
- Tasks can run from root (run task in all workspaces) or from child workspace dir
- Any executable we start in child workspace `cwd` should find its config there
- Each workspace contains its own `scripts` in `package.json`
- Each workspace contains its own dependencies
- Each workspace contains its own configuration files for dev, build, test, lint, etc.
- Configuration extension should be explicit and depends on tooling (e.g. `oxlint` has `extends`)
- We can add `extends` to `vite.config.ts`:

```ts
import { defineConfig } from "vite-plus";
export default defineConfig({
extends: "../../vite.config.ts"
});
```

## Example: `vite task build`

The "canonical" way using e.g. pnpm:

```sh
pnpm -F @repo/logger run build
pnpm -F @repo/next run build
pnpm -F @repo/spa run build
```

Btw, pnpm has `pnpm --recursive run build` which does topological sorting (
assuming it uses
[@pnpm/deps.graph-sequencer](https://github.com/pnpm/pnpm/tree/main/deps/graph-sequencer)).

With Vite+ (global CLI):

```sh
vite task build
```

- A task `build` is defined in `vite-task.json`
- `^build` syntax (Turborepo and Nx use this) → create dep graph from workspaces
- `apps/next` and `apps/spa` have `packages/logger` listed in `dependencies`
- take `build` from their `package.json#scripts`
- plan tasks
- run tasks
1. `tsdown`
2. `next build`
3. `vite build`

Could also run through package manager:

```sh
pnpm run build
```

As [package.json#scripts](./package.json) has `"build": "vite-plus task build"`.

## Config

[Task Design → Task Configuration](https://linear.app/voidzero/document/vite-task-design-doc-d6f7384ab696#heading-task-configuration-651cfdec)

Example [vite-task.json](./vite-task.json):

```json
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"cache": true
},
"dev": {
"dependsOn": ["@repo/logger#build"],
"cache": false,
"longRunning": true
}
}
}
```

Borrowed from Turborepo, I think overall it's good. Yet there are things that we
can probably optimize, e.g.:

- Default `dependsOn` to prefix with `^` (e.g. `"^build"`) and use
`package.json` dependencies to create graph
- Default to `cache: true` for `build` tasks
- Default to `cache: false` for `dev` tasks
- Defaults for output folders (e.g. `dist/**` for build tasks)

This should work well especially if we know that our own tools are being used.
We can also read from our own tooling's config e.g. to use non-default output
directory.

Here's a good example of how a configuration could be reduced significantly were
such defaults being applied:
https://github.com/motiondivision/motion/blob/main/turbo.json (perhaps even
zero-config).

## Execution

Simplified task execution graph:

```json
{
"tasks": [
[
{
"command": "tsdown",
"args": [],
"cwd": "packages/logger",
"cache": true
}
],
[
{
"command": "next",
"args": ["build"],
"cwd": "apps/next",
"cache": true
},
{
"command": "vite",
"args": ["build"],
"cwd": "apps/spa",
"cache": true
}
]
]
}
```

- Running `next` from `apps/next` and it will find its own `next.config.ts`
- Running `vite build` from child workspace will read `vite.config.ts` (which
might `extend` from root config)

## dev

If we would pre-build `packages/logger` and then watch the apps:

```json
{
"tasks": [
[
{
"command": "tsdown",
"args": [],
"cwd": "packages/logger",
"cache": true
}
],
[
{
"command": "next",
"args": ["dev"],
"cwd": "apps/next",
"cache": false
},
{
"command": "vite",
"args": ["dev"],
"cwd": "apps/spa",
"cache": false
}
]
]
}
```
5 changes: 5 additions & 0 deletions examples/example1/apps/next/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
1 change: 1 addition & 0 deletions examples/example1/apps/next/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {};
17 changes: 17 additions & 0 deletions examples/example1/apps/next/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@repo/next",
"scripts": {
"dev": "next dev",
"build": "next build"
},
"dependencies": {
"@repo/logger": "workspace:*",
"next": "^15.3.3",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6"
}
}
Binary file added examples/example1/apps/next/public/favicon.ico
Binary file not shown.
7 changes: 7 additions & 0 deletions examples/example1/apps/next/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
11 changes: 11 additions & 0 deletions examples/example1/apps/next/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import console from '@repo/logger';

export const metadata = {
title: 'My Page'
};

export default function MyPage() {
console.info('Next.js');

return <div>content</div>;
}
24 changes: 24 additions & 0 deletions examples/example1/apps/next/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"esModuleInterop": true,
"jsx": "preserve",
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"noEmit": true,
"incremental": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
1 change: 1 addition & 0 deletions examples/example1/apps/spa/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="module" src="./src/index.js"></script>
14 changes: 14 additions & 0 deletions examples/example1/apps/spa/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "@repo/spa",
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build"
},
"dependencies": {
"@repo/logger": "workspace:*"
},
"devDependencies": {
"vite": "^6.3.5"
}
}
3 changes: 3 additions & 0 deletions examples/example1/apps/spa/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { log } from "@repo/logger";

log("SPA");
5 changes: 5 additions & 0 deletions examples/example1/apps/spa/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from "vite-plus";

export default defineConfig({
base: "web"
});
8 changes: 8 additions & 0 deletions examples/example1/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@repo/root",
"private": true,
"type": "module",
"scripts": {
"build": "vite-plus task build"
}
}
6 changes: 6 additions & 0 deletions examples/example1/packages/logger/.oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": ["../../.oxlintrc.json"],
"rules": {
"no-eval": "error"
}
}
27 changes: 27 additions & 0 deletions examples/example1/packages/logger/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@repo/logger",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
},
"scripts": {
"build": "tsdown",
"test": "vitest",
"lint": "oxlint"
},
"devDependencies": {
"@types/node": "^24.0.3",
"oxlint": "^1.2.0",
"tsdown": "^0.12.8",
"typescript": "^5.8.3",
"vite-plus": "file:../../../../packages/cli",
"vitest": "^3.2.4"
}
}
4 changes: 4 additions & 0 deletions examples/example1/packages/logger/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const log = (msg: string) => console.log(msg);

// alert("eval");
// eval("alert");
11 changes: 11 additions & 0 deletions examples/example1/packages/logger/tests/log.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { test, expect } from "vitest";
import * as console from "@log/index.ts";
import { script1 } from "@scripts/script1.ts";

test("console", () => {
expect(console.log).toBeDefined();
});

test("script", () => {
expect(script1()).toBe("script 1");
});
13 changes: 13 additions & 0 deletions examples/example1/packages/logger/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"noEmit": true,
"module": "nodenext",
"moduleResolution": "nodenext",
"allowImportingTsExtensions": true,
"esModuleInterop": true,
"paths": {
"@log/*": ["./src/*"]
}
}
}
14 changes: 14 additions & 0 deletions examples/example1/packages/logger/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { join } from "node:path";
import { defineConfig } from "vite-plus";

export default defineConfig({
extends: "../../vite.config.ts",
resolve: {
alias: {
"@log": `${join(import.meta.dirname, "src")}`
}
},
test: {
reporters: ["dot"]
}
});
Loading