@vizejs/vite-plugin 0.0.1-alpha.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -0
- package/dist/index.d.ts +498 -0
- package/dist/index.js +542 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# @vizejs/vite-plugin
|
|
2
|
+
|
|
3
|
+
High-performance native Vite plugin for Vue SFC compilation powered by [Vize](https://github.com/ubugeeei/vize).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Native Performance**: Uses Rust-based compiler via Node.js native bindings (NAPI)
|
|
8
|
+
- **Pre-compilation**: All `.vue` files are compiled at server startup for instant module resolution
|
|
9
|
+
- **Virtual Modules**: Compiled code is served from memory as virtual modules
|
|
10
|
+
- **HMR Support**: Hot Module Replacement with automatic re-compilation on file changes
|
|
11
|
+
- **Vapor Mode**: Optional support for Vue Vapor mode compilation
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# npm
|
|
17
|
+
npm install @vizejs/vite-plugin
|
|
18
|
+
|
|
19
|
+
# pnpm
|
|
20
|
+
pnpm add @vizejs/vite-plugin
|
|
21
|
+
|
|
22
|
+
# yarn
|
|
23
|
+
yarn add @vizejs/vite-plugin
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Vite
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// vite.config.ts
|
|
32
|
+
import { defineConfig } from 'vite'
|
|
33
|
+
import vize from '@vizejs/vite-plugin'
|
|
34
|
+
|
|
35
|
+
export default defineConfig({
|
|
36
|
+
plugins: [
|
|
37
|
+
vize({
|
|
38
|
+
// options
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Nuxt
|
|
45
|
+
|
|
46
|
+
For Nuxt 3, add the plugin to your `nuxt.config.ts`:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
// nuxt.config.ts
|
|
50
|
+
import vize from '@vizejs/vite-plugin'
|
|
51
|
+
|
|
52
|
+
export default defineNuxtConfig({
|
|
53
|
+
vite: {
|
|
54
|
+
plugins: [
|
|
55
|
+
vize({
|
|
56
|
+
// Exclude Nuxt's internal .vue files if needed
|
|
57
|
+
exclude: [/node_modules/, /#/, /\.nuxt/]
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Disable the default Vue plugin
|
|
63
|
+
vue: {
|
|
64
|
+
propsDestructure: false
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Note**: When using with Nuxt, you may need to disable Nuxt's built-in Vue plugin to avoid conflicts:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// nuxt.config.ts
|
|
73
|
+
export default defineNuxtConfig({
|
|
74
|
+
hooks: {
|
|
75
|
+
'vite:extendConfig': (config) => {
|
|
76
|
+
// Remove @vitejs/plugin-vue from plugins
|
|
77
|
+
config.plugins = config.plugins?.filter(
|
|
78
|
+
(p) => p && (Array.isArray(p) ? p[0] : p).name !== 'vite:vue'
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
vite: {
|
|
83
|
+
plugins: [
|
|
84
|
+
vize()
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Options
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
interface VizeNativeOptions {
|
|
94
|
+
/**
|
|
95
|
+
* Files to include in compilation
|
|
96
|
+
* @default /\.vue$/
|
|
97
|
+
*/
|
|
98
|
+
include?: string | RegExp | (string | RegExp)[]
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Files to exclude from compilation
|
|
102
|
+
* @default /node_modules/
|
|
103
|
+
*/
|
|
104
|
+
exclude?: string | RegExp | (string | RegExp)[]
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Force production mode
|
|
108
|
+
* @default auto-detected from Vite config
|
|
109
|
+
*/
|
|
110
|
+
isProduction?: boolean
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Enable SSR mode
|
|
114
|
+
* @default false
|
|
115
|
+
*/
|
|
116
|
+
ssr?: boolean
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Enable source map generation
|
|
120
|
+
* @default true in development, false in production
|
|
121
|
+
*/
|
|
122
|
+
sourceMap?: boolean
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Enable Vapor mode compilation
|
|
126
|
+
* @default false
|
|
127
|
+
*/
|
|
128
|
+
vapor?: boolean
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Root directory to scan for .vue files
|
|
132
|
+
* @default Vite's root
|
|
133
|
+
*/
|
|
134
|
+
root?: string
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Glob patterns to scan for .vue files during pre-compilation
|
|
138
|
+
* @default ['**\/*.vue']
|
|
139
|
+
*/
|
|
140
|
+
scanPatterns?: string[]
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Glob patterns to ignore during pre-compilation
|
|
144
|
+
* @default ['node_modules/**', 'dist/**', '.git/**']
|
|
145
|
+
*/
|
|
146
|
+
ignorePatterns?: string[]
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## How It Works
|
|
151
|
+
|
|
152
|
+
### Pre-compilation at Startup
|
|
153
|
+
|
|
154
|
+
When the Vite dev server starts (or build begins), the plugin:
|
|
155
|
+
|
|
156
|
+
1. Scans the project root for all `.vue` files matching the configured patterns
|
|
157
|
+
2. Compiles each file using the native Vize compiler
|
|
158
|
+
3. Stores the compiled JavaScript and CSS in an in-memory cache
|
|
159
|
+
|
|
160
|
+
This approach leverages Vize's exceptional performance - compiling 15,000 SFC files in under 500ms with multi-threading.
|
|
161
|
+
|
|
162
|
+
### Virtual Module Resolution
|
|
163
|
+
|
|
164
|
+
When Vite requests a `.vue` file:
|
|
165
|
+
|
|
166
|
+
1. The plugin intercepts the module resolution
|
|
167
|
+
2. Returns the pre-compiled code from cache (or compiles on-demand if not cached)
|
|
168
|
+
3. CSS is injected inline with deduplication support
|
|
169
|
+
|
|
170
|
+
### HMR (Hot Module Replacement)
|
|
171
|
+
|
|
172
|
+
When a `.vue` file changes:
|
|
173
|
+
|
|
174
|
+
1. The plugin detects the change via `handleHotUpdate`
|
|
175
|
+
2. Re-compiles only the changed file
|
|
176
|
+
3. Updates the cache
|
|
177
|
+
4. Vite handles the rest of the HMR flow
|
|
178
|
+
|
|
179
|
+
## Performance
|
|
180
|
+
|
|
181
|
+
Vize's native compiler is significantly faster than the official Vue compiler:
|
|
182
|
+
|
|
183
|
+
| Benchmark (15,000 SFCs) | @vue/compiler-sfc | Vize | Speedup |
|
|
184
|
+
|-------------------------|-------------------|------|---------|
|
|
185
|
+
| Single-threaded | 16.21s | 6.65s | **2.4x** |
|
|
186
|
+
| Multi-threaded | 4.13s | 498ms | **8.3x** |
|
|
187
|
+
|
|
188
|
+
## Comparison with vite-plugin-vize
|
|
189
|
+
|
|
190
|
+
| Feature | vite-plugin-vize | vite-plugin-vize |
|
|
191
|
+
|---------|------------------|-------------------------|
|
|
192
|
+
| Compiler | WASM | Native (NAPI) |
|
|
193
|
+
| Pre-compilation | No | Yes |
|
|
194
|
+
| Module Loading | Transform | Virtual Module (Load) |
|
|
195
|
+
| Performance | Fast | Fastest |
|
|
196
|
+
| Platform | Any | Node.js only |
|
|
197
|
+
|
|
198
|
+
Use `vite-plugin-vize` (WASM-based) when you need:
|
|
199
|
+
- Browser compatibility (e.g., StackBlitz, WebContainers)
|
|
200
|
+
- Platform-independent deployment
|
|
201
|
+
|
|
202
|
+
Use `vite-plugin-vize` when you need:
|
|
203
|
+
- Maximum performance
|
|
204
|
+
- Server-side only (standard Node.js environment)
|
|
205
|
+
|
|
206
|
+
## Requirements
|
|
207
|
+
|
|
208
|
+
- Node.js 18+
|
|
209
|
+
- Vite 5.0+ / 6.0+ / 7.0+
|
|
210
|
+
- Vue 3.x
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region ../vize/src/types.d.ts
|
|
4
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
+
interface ConfigEnv {
|
|
6
|
+
mode: string;
|
|
7
|
+
command: "serve" | "build" | "check" | "lint" | "fmt";
|
|
8
|
+
isSsrBuild?: boolean;
|
|
9
|
+
}
|
|
10
|
+
type UserConfigExport = VizeConfig | ((env: ConfigEnv) => MaybePromise<VizeConfig>);
|
|
11
|
+
type RuleSeverity = "off" | "warn" | "error";
|
|
12
|
+
type RuleCategory = "correctness" | "suspicious" | "style" | "perf" | "a11y" | "security";
|
|
13
|
+
/**
|
|
14
|
+
* Vize configuration options
|
|
15
|
+
*/
|
|
16
|
+
interface VizeConfig {
|
|
17
|
+
/**
|
|
18
|
+
* Vue compiler options
|
|
19
|
+
*/
|
|
20
|
+
compiler?: CompilerConfig;
|
|
21
|
+
/**
|
|
22
|
+
* Vite plugin options
|
|
23
|
+
*/
|
|
24
|
+
vite?: VitePluginConfig;
|
|
25
|
+
/**
|
|
26
|
+
* Linter options
|
|
27
|
+
*/
|
|
28
|
+
linter?: LinterConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Type checker options
|
|
31
|
+
*/
|
|
32
|
+
typeChecker?: TypeCheckerConfig;
|
|
33
|
+
/**
|
|
34
|
+
* Formatter options
|
|
35
|
+
*/
|
|
36
|
+
formatter?: FormatterConfig;
|
|
37
|
+
/**
|
|
38
|
+
* LSP options
|
|
39
|
+
*/
|
|
40
|
+
lsp?: LspConfig;
|
|
41
|
+
/**
|
|
42
|
+
* Musea component gallery options
|
|
43
|
+
*/
|
|
44
|
+
musea?: MuseaConfig;
|
|
45
|
+
/**
|
|
46
|
+
* Global type declarations
|
|
47
|
+
*/
|
|
48
|
+
globalTypes?: GlobalTypesConfig;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compiler configuration
|
|
52
|
+
*/
|
|
53
|
+
interface CompilerConfig {
|
|
54
|
+
/**
|
|
55
|
+
* Compilation mode
|
|
56
|
+
* @default 'module'
|
|
57
|
+
*/
|
|
58
|
+
mode?: "module" | "function";
|
|
59
|
+
/**
|
|
60
|
+
* Enable Vapor mode compilation
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
vapor?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Enable SSR mode
|
|
66
|
+
* @default false
|
|
67
|
+
*/
|
|
68
|
+
ssr?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Enable source map generation
|
|
71
|
+
* @default true in development, false in production
|
|
72
|
+
*/
|
|
73
|
+
sourceMap?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Prefix template identifiers with _ctx
|
|
76
|
+
* @default false
|
|
77
|
+
*/
|
|
78
|
+
prefixIdentifiers?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Hoist static nodes
|
|
81
|
+
* @default true
|
|
82
|
+
*/
|
|
83
|
+
hoistStatic?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Cache v-on handlers
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
cacheHandlers?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Enable TypeScript parsing in <script> blocks
|
|
91
|
+
* @default true
|
|
92
|
+
*/
|
|
93
|
+
isTs?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Script file extension for generated output
|
|
96
|
+
* @default 'ts'
|
|
97
|
+
*/
|
|
98
|
+
scriptExt?: "ts" | "js";
|
|
99
|
+
/**
|
|
100
|
+
* Module name for runtime imports
|
|
101
|
+
* @default 'vue'
|
|
102
|
+
*/
|
|
103
|
+
runtimeModuleName?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Global variable name for runtime (IIFE builds)
|
|
106
|
+
* @default 'Vue'
|
|
107
|
+
*/
|
|
108
|
+
runtimeGlobalName?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Vite plugin configuration
|
|
112
|
+
*/
|
|
113
|
+
interface VitePluginConfig {
|
|
114
|
+
/**
|
|
115
|
+
* Files to include in compilation
|
|
116
|
+
* @default /\.vue$/
|
|
117
|
+
*/
|
|
118
|
+
include?: string | RegExp | (string | RegExp)[];
|
|
119
|
+
/**
|
|
120
|
+
* Files to exclude from compilation
|
|
121
|
+
* @default /node_modules/
|
|
122
|
+
*/
|
|
123
|
+
exclude?: string | RegExp | (string | RegExp)[];
|
|
124
|
+
/**
|
|
125
|
+
* Glob patterns to scan for .vue files during pre-compilation
|
|
126
|
+
* @default ['**\/*.vue']
|
|
127
|
+
*/
|
|
128
|
+
scanPatterns?: string[];
|
|
129
|
+
/**
|
|
130
|
+
* Glob patterns to ignore during pre-compilation
|
|
131
|
+
* @default ['node_modules/**', 'dist/**', '.git/**']
|
|
132
|
+
*/
|
|
133
|
+
ignorePatterns?: string[];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Linter configuration
|
|
137
|
+
*/
|
|
138
|
+
interface LinterConfig {
|
|
139
|
+
/**
|
|
140
|
+
* Enable linting
|
|
141
|
+
*/
|
|
142
|
+
enabled?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Rules to enable/disable
|
|
145
|
+
*/
|
|
146
|
+
rules?: Record<string, RuleSeverity>;
|
|
147
|
+
/**
|
|
148
|
+
* Category-level severity overrides
|
|
149
|
+
*/
|
|
150
|
+
categories?: Partial<Record<RuleCategory, RuleSeverity>>;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Type checker configuration
|
|
154
|
+
*/
|
|
155
|
+
interface TypeCheckerConfig {
|
|
156
|
+
/**
|
|
157
|
+
* Enable type checking
|
|
158
|
+
* @default false
|
|
159
|
+
*/
|
|
160
|
+
enabled?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Enable strict mode
|
|
163
|
+
* @default false
|
|
164
|
+
*/
|
|
165
|
+
strict?: boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Check component props
|
|
168
|
+
* @default true
|
|
169
|
+
*/
|
|
170
|
+
checkProps?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Check component emits
|
|
173
|
+
* @default true
|
|
174
|
+
*/
|
|
175
|
+
checkEmits?: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Check template bindings
|
|
178
|
+
* @default true
|
|
179
|
+
*/
|
|
180
|
+
checkTemplateBindings?: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Path to tsconfig.json
|
|
183
|
+
* @default auto-detected
|
|
184
|
+
*/
|
|
185
|
+
tsconfig?: string;
|
|
186
|
+
/**
|
|
187
|
+
* Path to tsgo binary
|
|
188
|
+
*/
|
|
189
|
+
tsgoPath?: string;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Formatter configuration
|
|
193
|
+
*/
|
|
194
|
+
interface FormatterConfig {
|
|
195
|
+
/**
|
|
196
|
+
* Max line width
|
|
197
|
+
* @default 80
|
|
198
|
+
*/
|
|
199
|
+
printWidth?: number;
|
|
200
|
+
/**
|
|
201
|
+
* Indentation width
|
|
202
|
+
* @default 2
|
|
203
|
+
*/
|
|
204
|
+
tabWidth?: number;
|
|
205
|
+
/**
|
|
206
|
+
* Use tabs for indentation
|
|
207
|
+
* @default false
|
|
208
|
+
*/
|
|
209
|
+
useTabs?: boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Print semicolons
|
|
212
|
+
* @default true
|
|
213
|
+
*/
|
|
214
|
+
semi?: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* Use single quotes
|
|
217
|
+
* @default false
|
|
218
|
+
*/
|
|
219
|
+
singleQuote?: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Trailing commas
|
|
222
|
+
* @default 'all'
|
|
223
|
+
*/
|
|
224
|
+
trailingComma?: "all" | "none" | "es5";
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* LSP configuration
|
|
228
|
+
*/
|
|
229
|
+
interface LspConfig {
|
|
230
|
+
/**
|
|
231
|
+
* Enable LSP
|
|
232
|
+
* @default true
|
|
233
|
+
*/
|
|
234
|
+
enabled?: boolean;
|
|
235
|
+
/**
|
|
236
|
+
* Enable diagnostics
|
|
237
|
+
* @default true
|
|
238
|
+
*/
|
|
239
|
+
diagnostics?: boolean;
|
|
240
|
+
/**
|
|
241
|
+
* Enable completions
|
|
242
|
+
* @default true
|
|
243
|
+
*/
|
|
244
|
+
completion?: boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Enable hover information
|
|
247
|
+
* @default true
|
|
248
|
+
*/
|
|
249
|
+
hover?: boolean;
|
|
250
|
+
/**
|
|
251
|
+
* Enable go-to-definition
|
|
252
|
+
* @default true
|
|
253
|
+
*/
|
|
254
|
+
definition?: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Enable formatting via LSP
|
|
257
|
+
* @default true
|
|
258
|
+
*/
|
|
259
|
+
formatting?: boolean;
|
|
260
|
+
/**
|
|
261
|
+
* Enable code actions
|
|
262
|
+
* @default true
|
|
263
|
+
*/
|
|
264
|
+
codeActions?: boolean;
|
|
265
|
+
/**
|
|
266
|
+
* Use tsgo for type checking in LSP
|
|
267
|
+
* @default false
|
|
268
|
+
*/
|
|
269
|
+
tsgo?: boolean;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* VRT (Visual Regression Testing) configuration for Musea
|
|
273
|
+
*/
|
|
274
|
+
interface MuseaVrtConfig {
|
|
275
|
+
/**
|
|
276
|
+
* Threshold for pixel comparison (0-1)
|
|
277
|
+
* @default 0.1
|
|
278
|
+
*/
|
|
279
|
+
threshold?: number;
|
|
280
|
+
/**
|
|
281
|
+
* Output directory for screenshots
|
|
282
|
+
* @default '__musea_snapshots__'
|
|
283
|
+
*/
|
|
284
|
+
outDir?: string;
|
|
285
|
+
/**
|
|
286
|
+
* Viewport sizes
|
|
287
|
+
*/
|
|
288
|
+
viewports?: Array<{
|
|
289
|
+
width: number;
|
|
290
|
+
height: number;
|
|
291
|
+
name?: string;
|
|
292
|
+
}>;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* A11y configuration for Musea
|
|
296
|
+
*/
|
|
297
|
+
interface MuseaA11yConfig {
|
|
298
|
+
/**
|
|
299
|
+
* Enable a11y checking
|
|
300
|
+
* @default false
|
|
301
|
+
*/
|
|
302
|
+
enabled?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Axe-core rules to enable/disable
|
|
305
|
+
*/
|
|
306
|
+
rules?: Record<string, boolean>;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Autogen configuration for Musea
|
|
310
|
+
*/
|
|
311
|
+
interface MuseaAutogenConfig {
|
|
312
|
+
/**
|
|
313
|
+
* Enable auto-generation of variants
|
|
314
|
+
* @default false
|
|
315
|
+
*/
|
|
316
|
+
enabled?: boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Max variants to generate per component
|
|
319
|
+
* @default 10
|
|
320
|
+
*/
|
|
321
|
+
maxVariants?: number;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Musea component gallery configuration
|
|
325
|
+
*/
|
|
326
|
+
interface MuseaConfig {
|
|
327
|
+
/**
|
|
328
|
+
* Glob patterns for art files
|
|
329
|
+
* @default ['**\/*.art.vue']
|
|
330
|
+
*/
|
|
331
|
+
include?: string[];
|
|
332
|
+
/**
|
|
333
|
+
* Glob patterns to exclude
|
|
334
|
+
* @default ['node_modules/**', 'dist/**']
|
|
335
|
+
*/
|
|
336
|
+
exclude?: string[];
|
|
337
|
+
/**
|
|
338
|
+
* Base path for gallery
|
|
339
|
+
* @default '/__musea__'
|
|
340
|
+
*/
|
|
341
|
+
basePath?: string;
|
|
342
|
+
/**
|
|
343
|
+
* Enable Storybook compatibility
|
|
344
|
+
* @default false
|
|
345
|
+
*/
|
|
346
|
+
storybookCompat?: boolean;
|
|
347
|
+
/**
|
|
348
|
+
* Enable inline art detection in .vue files
|
|
349
|
+
* @default false
|
|
350
|
+
*/
|
|
351
|
+
inlineArt?: boolean;
|
|
352
|
+
/**
|
|
353
|
+
* VRT configuration
|
|
354
|
+
*/
|
|
355
|
+
vrt?: MuseaVrtConfig;
|
|
356
|
+
/**
|
|
357
|
+
* A11y configuration
|
|
358
|
+
*/
|
|
359
|
+
a11y?: MuseaA11yConfig;
|
|
360
|
+
/**
|
|
361
|
+
* Autogen configuration
|
|
362
|
+
*/
|
|
363
|
+
autogen?: MuseaAutogenConfig;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Global type declaration
|
|
367
|
+
*/
|
|
368
|
+
interface GlobalTypeDeclaration {
|
|
369
|
+
/**
|
|
370
|
+
* TypeScript type string
|
|
371
|
+
*/
|
|
372
|
+
type: string;
|
|
373
|
+
/**
|
|
374
|
+
* Default value
|
|
375
|
+
*/
|
|
376
|
+
defaultValue?: string;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Global types configuration
|
|
380
|
+
*/
|
|
381
|
+
type GlobalTypesConfig = Record<string, GlobalTypeDeclaration | string>;
|
|
382
|
+
/**
|
|
383
|
+
* Options for loading vize.config file
|
|
384
|
+
*/
|
|
385
|
+
interface LoadConfigOptions {
|
|
386
|
+
/**
|
|
387
|
+
* Config file search mode
|
|
388
|
+
* - 'root': Search only in the specified root directory
|
|
389
|
+
* - 'auto': Search from cwd upward until finding a config file
|
|
390
|
+
* - 'none': Don't load config file
|
|
391
|
+
* @default 'root'
|
|
392
|
+
*/
|
|
393
|
+
mode?: "root" | "auto" | "none";
|
|
394
|
+
/**
|
|
395
|
+
* Custom config file path (overrides automatic search)
|
|
396
|
+
*/
|
|
397
|
+
configFile?: string;
|
|
398
|
+
/**
|
|
399
|
+
* Config environment for dynamic config resolution
|
|
400
|
+
*/
|
|
401
|
+
env?: ConfigEnv;
|
|
402
|
+
} //#endregion
|
|
403
|
+
//#region src/types.d.ts
|
|
404
|
+
interface VizeOptions {
|
|
405
|
+
/**
|
|
406
|
+
* Files to include in compilation
|
|
407
|
+
* @default /\.vue$/
|
|
408
|
+
*/
|
|
409
|
+
include?: string | RegExp | (string | RegExp)[];
|
|
410
|
+
/**
|
|
411
|
+
* Files to exclude from compilation
|
|
412
|
+
* @default /node_modules/
|
|
413
|
+
*/
|
|
414
|
+
exclude?: string | RegExp | (string | RegExp)[];
|
|
415
|
+
/**
|
|
416
|
+
* Force production mode
|
|
417
|
+
* @default auto-detected from Vite config
|
|
418
|
+
*/
|
|
419
|
+
isProduction?: boolean;
|
|
420
|
+
/**
|
|
421
|
+
* Enable SSR mode
|
|
422
|
+
* @default false
|
|
423
|
+
*/
|
|
424
|
+
ssr?: boolean;
|
|
425
|
+
/**
|
|
426
|
+
* Enable source map generation
|
|
427
|
+
* @default true in development, false in production
|
|
428
|
+
*/
|
|
429
|
+
sourceMap?: boolean;
|
|
430
|
+
/**
|
|
431
|
+
* Enable Vapor mode compilation
|
|
432
|
+
* @default false
|
|
433
|
+
*/
|
|
434
|
+
vapor?: boolean;
|
|
435
|
+
/**
|
|
436
|
+
* Root directory to scan for .vue files
|
|
437
|
+
* @default Vite's root
|
|
438
|
+
*/
|
|
439
|
+
root?: string;
|
|
440
|
+
/**
|
|
441
|
+
* Glob patterns to scan for .vue files during pre-compilation
|
|
442
|
+
* @default ['**\/*.vue']
|
|
443
|
+
*/
|
|
444
|
+
scanPatterns?: string[];
|
|
445
|
+
/**
|
|
446
|
+
* Glob patterns to ignore during pre-compilation
|
|
447
|
+
* @default ['node_modules/**', 'dist/**', '.git/**']
|
|
448
|
+
*/
|
|
449
|
+
ignorePatterns?: string[];
|
|
450
|
+
/**
|
|
451
|
+
* Config file search mode
|
|
452
|
+
* - 'root': Search only in the project root directory
|
|
453
|
+
* - 'auto': Search from cwd upward until finding a config file
|
|
454
|
+
* - false: Disable config file loading
|
|
455
|
+
* @default 'root'
|
|
456
|
+
*/
|
|
457
|
+
configMode?: "root" | "auto" | false;
|
|
458
|
+
/**
|
|
459
|
+
* Custom config file path (overrides automatic search)
|
|
460
|
+
*/
|
|
461
|
+
configFile?: string;
|
|
462
|
+
/**
|
|
463
|
+
* Enable debug logging
|
|
464
|
+
* @default false
|
|
465
|
+
*/
|
|
466
|
+
debug?: boolean;
|
|
467
|
+
}
|
|
468
|
+
interface CompiledModule {
|
|
469
|
+
code: string;
|
|
470
|
+
css?: string;
|
|
471
|
+
scopeId: string;
|
|
472
|
+
hasScoped: boolean;
|
|
473
|
+
templateHash?: string;
|
|
474
|
+
styleHash?: string;
|
|
475
|
+
scriptHash?: string;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/index.d.ts
|
|
480
|
+
/**
|
|
481
|
+
* Define a Vize configuration with type checking.
|
|
482
|
+
* Accepts a plain object or a function that receives ConfigEnv.
|
|
483
|
+
*/
|
|
484
|
+
declare function defineConfig(config: UserConfigExport): UserConfigExport;
|
|
485
|
+
/**
|
|
486
|
+
* Load Vize configuration from file
|
|
487
|
+
*/
|
|
488
|
+
declare function loadConfig(root: string, options?: LoadConfigOptions): Promise<VizeConfig | null>;
|
|
489
|
+
/**
|
|
490
|
+
* Shared config store for inter-plugin communication.
|
|
491
|
+
* Key = project root, Value = resolved VizeConfig.
|
|
492
|
+
* Used by musea() and other plugins to access the unified config.
|
|
493
|
+
*/
|
|
494
|
+
declare const vizeConfigStore: Map<string, VizeConfig>;
|
|
495
|
+
declare function vize(options?: VizeOptions): Plugin;
|
|
496
|
+
|
|
497
|
+
//#endregion
|
|
498
|
+
export { CompiledModule, LoadConfigOptions, VizeConfig, VizeOptions, vize as default, defineConfig, loadConfig, vize, vizeConfigStore };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import { transformWithOxc } from "vite";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import { glob } from "tinyglobby";
|
|
5
|
+
import * as native from "@vizejs/native";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
|
|
8
|
+
//#region src/hmr.ts
|
|
9
|
+
/**
|
|
10
|
+
* Detect the type of HMR update needed based on content hash changes.
|
|
11
|
+
*
|
|
12
|
+
* @param prev - Previously compiled module (undefined if first compile)
|
|
13
|
+
* @param next - Newly compiled module
|
|
14
|
+
* @returns The type of HMR update needed
|
|
15
|
+
*/
|
|
16
|
+
function detectHmrUpdateType(prev, next) {
|
|
17
|
+
if (!prev) return "full-reload";
|
|
18
|
+
const scriptChanged = prev.scriptHash !== next.scriptHash;
|
|
19
|
+
if (scriptChanged) return "full-reload";
|
|
20
|
+
const templateChanged = prev.templateHash !== next.templateHash;
|
|
21
|
+
const styleChanged = prev.styleHash !== next.styleHash;
|
|
22
|
+
if (styleChanged && !templateChanged) return "style-only";
|
|
23
|
+
if (templateChanged) return "template-only";
|
|
24
|
+
return "full-reload";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate HMR-aware code output based on update type.
|
|
28
|
+
*/
|
|
29
|
+
function generateHmrCode(scopeId, updateType) {
|
|
30
|
+
return `
|
|
31
|
+
if (import.meta.hot) {
|
|
32
|
+
_sfc_main.__hmrId = ${JSON.stringify(scopeId)};
|
|
33
|
+
_sfc_main.__hmrUpdateType = ${JSON.stringify(updateType)};
|
|
34
|
+
|
|
35
|
+
import.meta.hot.accept((mod) => {
|
|
36
|
+
if (!mod) return;
|
|
37
|
+
const { default: updated } = mod;
|
|
38
|
+
if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
|
|
39
|
+
const updateType = updated.__hmrUpdateType || 'full-reload';
|
|
40
|
+
if (updateType === 'template-only') {
|
|
41
|
+
__VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render);
|
|
42
|
+
} else {
|
|
43
|
+
__VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
import.meta.hot.on('vize:update', (data) => {
|
|
49
|
+
if (data.id !== _sfc_main.__hmrId) return;
|
|
50
|
+
|
|
51
|
+
if (data.type === 'style-only') {
|
|
52
|
+
// Update styles without remounting component
|
|
53
|
+
const styleId = 'vize-style-' + _sfc_main.__hmrId;
|
|
54
|
+
const styleEl = document.getElementById(styleId);
|
|
55
|
+
if (styleEl && data.css) {
|
|
56
|
+
styleEl.textContent = data.css;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
|
|
62
|
+
__VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main);
|
|
63
|
+
}
|
|
64
|
+
}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/utils.ts
|
|
69
|
+
function generateScopeId(filename) {
|
|
70
|
+
const hash = createHash("sha256").update(filename).digest("hex");
|
|
71
|
+
return hash.slice(0, 8);
|
|
72
|
+
}
|
|
73
|
+
function createFilter(include, exclude) {
|
|
74
|
+
const includePatterns = include ? Array.isArray(include) ? include : [include] : [/\.vue$/];
|
|
75
|
+
const excludePatterns = exclude ? Array.isArray(exclude) ? exclude : [exclude] : [/node_modules/];
|
|
76
|
+
return (id) => {
|
|
77
|
+
const matchInclude = includePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
|
|
78
|
+
const matchExclude = excludePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
|
|
79
|
+
return matchInclude && !matchExclude;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function generateOutput(compiled, options) {
|
|
83
|
+
const { isProduction, isDev, hmrUpdateType, extractCss } = options;
|
|
84
|
+
let output = compiled.code;
|
|
85
|
+
const exportDefaultRegex = /^export default /m;
|
|
86
|
+
const hasExportDefault = exportDefaultRegex.test(output);
|
|
87
|
+
const hasSfcMainDefined = /\bconst\s+_sfc_main\s*=/.test(output);
|
|
88
|
+
if (hasExportDefault && !hasSfcMainDefined) {
|
|
89
|
+
output = output.replace(exportDefaultRegex, "const _sfc_main = ");
|
|
90
|
+
if (compiled.hasScoped && compiled.scopeId) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
|
|
91
|
+
output += "\nexport default _sfc_main;";
|
|
92
|
+
} else if (hasExportDefault && hasSfcMainDefined) {
|
|
93
|
+
if (compiled.hasScoped && compiled.scopeId) output = output.replace(/^export default _sfc_main/m, `_sfc_main.__scopeId = "data-v-${compiled.scopeId}";\nexport default _sfc_main`);
|
|
94
|
+
}
|
|
95
|
+
if (compiled.css && !(isProduction && extractCss)) {
|
|
96
|
+
const cssCode = JSON.stringify(compiled.css);
|
|
97
|
+
const cssId = JSON.stringify(`vize-style-${compiled.scopeId}`);
|
|
98
|
+
output = `
|
|
99
|
+
const __vize_css__ = ${cssCode};
|
|
100
|
+
const __vize_css_id__ = ${cssId};
|
|
101
|
+
(function() {
|
|
102
|
+
if (typeof document !== 'undefined') {
|
|
103
|
+
let style = document.getElementById(__vize_css_id__);
|
|
104
|
+
if (!style) {
|
|
105
|
+
style = document.createElement('style');
|
|
106
|
+
style.id = __vize_css_id__;
|
|
107
|
+
style.textContent = __vize_css__;
|
|
108
|
+
document.head.appendChild(style);
|
|
109
|
+
} else {
|
|
110
|
+
style.textContent = __vize_css__;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
${output}`;
|
|
115
|
+
}
|
|
116
|
+
if (!isProduction && isDev && hasExportDefault) output += generateHmrCode(compiled.scopeId, hmrUpdateType ?? "full-reload");
|
|
117
|
+
return output;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/compiler.ts
|
|
122
|
+
const { compileSfc, compileSfcBatchWithResults } = native;
|
|
123
|
+
function compileFile(filePath, cache, options, source) {
|
|
124
|
+
const content = source ?? fs.readFileSync(filePath, "utf-8");
|
|
125
|
+
const scopeId = generateScopeId(filePath);
|
|
126
|
+
const hasScoped = /<style[^>]*\bscoped\b/.test(content);
|
|
127
|
+
const result = compileSfc(content, {
|
|
128
|
+
filename: filePath,
|
|
129
|
+
sourceMap: options.sourceMap,
|
|
130
|
+
ssr: options.ssr,
|
|
131
|
+
scopeId: hasScoped ? `data-v-${scopeId}` : void 0
|
|
132
|
+
});
|
|
133
|
+
if (result.errors.length > 0) {
|
|
134
|
+
const errorMsg = result.errors.join("\n");
|
|
135
|
+
console.error(`[vize] Compilation error in ${filePath}:\n${errorMsg}`);
|
|
136
|
+
}
|
|
137
|
+
if (result.warnings.length > 0) result.warnings.forEach((warning) => {
|
|
138
|
+
console.warn(`[vize] Warning in ${filePath}: ${warning}`);
|
|
139
|
+
});
|
|
140
|
+
const compiled = {
|
|
141
|
+
code: result.code,
|
|
142
|
+
css: result.css,
|
|
143
|
+
scopeId,
|
|
144
|
+
hasScoped
|
|
145
|
+
};
|
|
146
|
+
cache.set(filePath, compiled);
|
|
147
|
+
return compiled;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Batch compile multiple files in parallel using native Rust multithreading.
|
|
151
|
+
* Returns per-file results with content hashes for HMR.
|
|
152
|
+
*/
|
|
153
|
+
function compileBatch(files, cache, options) {
|
|
154
|
+
const inputs = files.map((f) => ({
|
|
155
|
+
path: f.path,
|
|
156
|
+
source: f.source
|
|
157
|
+
}));
|
|
158
|
+
const result = compileSfcBatchWithResults(inputs, { ssr: options.ssr });
|
|
159
|
+
for (const fileResult of result.results) {
|
|
160
|
+
if (fileResult.errors.length === 0) cache.set(fileResult.path, {
|
|
161
|
+
code: fileResult.code,
|
|
162
|
+
css: fileResult.css,
|
|
163
|
+
scopeId: fileResult.scopeId,
|
|
164
|
+
hasScoped: fileResult.hasScoped,
|
|
165
|
+
templateHash: fileResult.templateHash,
|
|
166
|
+
styleHash: fileResult.styleHash,
|
|
167
|
+
scriptHash: fileResult.scriptHash
|
|
168
|
+
});
|
|
169
|
+
if (fileResult.errors.length > 0) console.error(`[vize] Compilation error in ${fileResult.path}:\n${fileResult.errors.join("\n")}`);
|
|
170
|
+
if (fileResult.warnings.length > 0) fileResult.warnings.forEach((warning) => {
|
|
171
|
+
console.warn(`[vize] Warning in ${fileResult.path}: ${warning}`);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/index.ts
|
|
179
|
+
const CONFIG_FILES = [
|
|
180
|
+
"vize.config.ts",
|
|
181
|
+
"vize.config.js",
|
|
182
|
+
"vize.config.mjs",
|
|
183
|
+
"vize.config.json"
|
|
184
|
+
];
|
|
185
|
+
const DEFAULT_CONFIG_ENV = {
|
|
186
|
+
mode: "development",
|
|
187
|
+
command: "serve"
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Define a Vize configuration with type checking.
|
|
191
|
+
* Accepts a plain object or a function that receives ConfigEnv.
|
|
192
|
+
*/
|
|
193
|
+
function defineConfig(config) {
|
|
194
|
+
return config;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Load Vize configuration from file
|
|
198
|
+
*/
|
|
199
|
+
async function loadConfig(root, options = {}) {
|
|
200
|
+
const { mode = "root", configFile, env } = options;
|
|
201
|
+
if (mode === "none") return null;
|
|
202
|
+
if (configFile) {
|
|
203
|
+
const configPath = path.isAbsolute(configFile) ? configFile : path.resolve(root, configFile);
|
|
204
|
+
return loadConfigFile(configPath, env);
|
|
205
|
+
}
|
|
206
|
+
if (mode === "auto") {
|
|
207
|
+
let searchDir = root;
|
|
208
|
+
while (true) {
|
|
209
|
+
const found$1 = findConfigInDir(searchDir);
|
|
210
|
+
if (found$1) return loadConfigFile(found$1, env);
|
|
211
|
+
const parentDir = path.dirname(searchDir);
|
|
212
|
+
if (parentDir === searchDir) break;
|
|
213
|
+
searchDir = parentDir;
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
const found = findConfigInDir(root);
|
|
218
|
+
return found ? loadConfigFile(found, env) : null;
|
|
219
|
+
}
|
|
220
|
+
function findConfigInDir(dir) {
|
|
221
|
+
for (const filename of CONFIG_FILES) {
|
|
222
|
+
const configPath = path.join(dir, filename);
|
|
223
|
+
if (fs.existsSync(configPath)) return configPath;
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
async function resolveConfigExport(exported, env) {
|
|
228
|
+
if (typeof exported === "function") return exported(env ?? DEFAULT_CONFIG_ENV);
|
|
229
|
+
return exported;
|
|
230
|
+
}
|
|
231
|
+
async function loadConfigFile(configPath, env) {
|
|
232
|
+
if (!fs.existsSync(configPath)) return null;
|
|
233
|
+
const ext = path.extname(configPath);
|
|
234
|
+
if (ext === ".json") {
|
|
235
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
236
|
+
return JSON.parse(content);
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const module = await import(configPath);
|
|
240
|
+
const exported = module.default ?? module;
|
|
241
|
+
return resolveConfigExport(exported, env);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
console.warn(`[vize] Failed to load config from ${configPath}:`, e);
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Shared config store for inter-plugin communication.
|
|
249
|
+
* Key = project root, Value = resolved VizeConfig.
|
|
250
|
+
* Used by musea() and other plugins to access the unified config.
|
|
251
|
+
*/
|
|
252
|
+
const vizeConfigStore = new Map();
|
|
253
|
+
const VIRTUAL_PREFIX = "\0vize:";
|
|
254
|
+
const VIRTUAL_CSS_MODULE = "virtual:vize-styles";
|
|
255
|
+
const RESOLVED_CSS_MODULE = "\0vize:all-styles.css";
|
|
256
|
+
function createLogger(debug) {
|
|
257
|
+
return {
|
|
258
|
+
log: (...args) => debug && console.log("[vize]", ...args),
|
|
259
|
+
info: (...args) => console.log("[vize]", ...args),
|
|
260
|
+
warn: (...args) => console.warn("[vize]", ...args),
|
|
261
|
+
error: (...args) => console.error("[vize]", ...args)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function vize(options = {}) {
|
|
265
|
+
const cache = new Map();
|
|
266
|
+
const virtualToReal = new Map();
|
|
267
|
+
const collectedCss = new Map();
|
|
268
|
+
let isProduction;
|
|
269
|
+
let root;
|
|
270
|
+
let server = null;
|
|
271
|
+
let filter;
|
|
272
|
+
let scanPatterns;
|
|
273
|
+
let ignorePatterns;
|
|
274
|
+
let mergedOptions;
|
|
275
|
+
let extractCss = false;
|
|
276
|
+
const logger = createLogger(options.debug ?? false);
|
|
277
|
+
async function compileAll() {
|
|
278
|
+
const startTime = performance.now();
|
|
279
|
+
const files = await glob(scanPatterns, {
|
|
280
|
+
cwd: root,
|
|
281
|
+
ignore: ignorePatterns,
|
|
282
|
+
absolute: true
|
|
283
|
+
});
|
|
284
|
+
logger.info(`Pre-compiling ${files.length} Vue files...`);
|
|
285
|
+
const fileContents = [];
|
|
286
|
+
for (const file of files) try {
|
|
287
|
+
const source = fs.readFileSync(file, "utf-8");
|
|
288
|
+
fileContents.push({
|
|
289
|
+
path: file,
|
|
290
|
+
source
|
|
291
|
+
});
|
|
292
|
+
} catch (e) {
|
|
293
|
+
logger.error(`Failed to read ${file}:`, e);
|
|
294
|
+
}
|
|
295
|
+
const result = compileBatch(fileContents, cache, { ssr: mergedOptions.ssr ?? false });
|
|
296
|
+
if (isProduction) {
|
|
297
|
+
for (const fileResult of result.results) if (fileResult.css) collectedCss.set(fileResult.path, fileResult.css);
|
|
298
|
+
}
|
|
299
|
+
const elapsed = (performance.now() - startTime).toFixed(2);
|
|
300
|
+
logger.info(`Pre-compilation complete: ${result.successCount} succeeded, ${result.failedCount} failed (${elapsed}ms, native batch: ${result.timeMs.toFixed(2)}ms)`);
|
|
301
|
+
}
|
|
302
|
+
function resolveVuePath(id, importer) {
|
|
303
|
+
let resolved;
|
|
304
|
+
if (id.startsWith("/@fs/")) resolved = id.slice(4);
|
|
305
|
+
else if (id.startsWith("/") && !fs.existsSync(id)) resolved = path.resolve(root, id.slice(1));
|
|
306
|
+
else if (path.isAbsolute(id)) resolved = id;
|
|
307
|
+
else if (importer) {
|
|
308
|
+
let realImporter = importer.startsWith(VIRTUAL_PREFIX) ? virtualToReal.get(importer) ?? importer.slice(VIRTUAL_PREFIX.length) : importer;
|
|
309
|
+
if (realImporter.endsWith(".vue.ts")) realImporter = realImporter.slice(0, -3);
|
|
310
|
+
resolved = path.resolve(path.dirname(realImporter), id);
|
|
311
|
+
} else resolved = path.resolve(root, id);
|
|
312
|
+
if (!path.isAbsolute(resolved)) resolved = path.resolve(root, resolved);
|
|
313
|
+
return path.normalize(resolved);
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
name: "vite-plugin-vize",
|
|
317
|
+
enforce: "pre",
|
|
318
|
+
config() {
|
|
319
|
+
return { optimizeDeps: {
|
|
320
|
+
include: ["vue"],
|
|
321
|
+
exclude: ["virtual:vize-styles"],
|
|
322
|
+
esbuildOptions: { plugins: [{
|
|
323
|
+
name: "vize-externalize-vue",
|
|
324
|
+
setup(build) {
|
|
325
|
+
build.onResolve({ filter: /\.vue$/ }, (args) => ({
|
|
326
|
+
path: args.path,
|
|
327
|
+
external: true
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
}] },
|
|
331
|
+
rolldownOptions: { external: [/\.vue$/] }
|
|
332
|
+
} };
|
|
333
|
+
},
|
|
334
|
+
async configResolved(resolvedConfig) {
|
|
335
|
+
root = options.root ?? resolvedConfig.root;
|
|
336
|
+
isProduction = options.isProduction ?? resolvedConfig.isProduction;
|
|
337
|
+
extractCss = isProduction;
|
|
338
|
+
const configEnv = {
|
|
339
|
+
mode: resolvedConfig.mode,
|
|
340
|
+
command: resolvedConfig.command === "build" ? "build" : "serve",
|
|
341
|
+
isSsrBuild: !!resolvedConfig.build?.ssr
|
|
342
|
+
};
|
|
343
|
+
let fileConfig = null;
|
|
344
|
+
if (options.configMode !== false) {
|
|
345
|
+
fileConfig = await loadConfig(root, {
|
|
346
|
+
mode: options.configMode ?? "root",
|
|
347
|
+
configFile: options.configFile,
|
|
348
|
+
env: configEnv
|
|
349
|
+
});
|
|
350
|
+
if (fileConfig) {
|
|
351
|
+
logger.log("Loaded config from vize.config file");
|
|
352
|
+
vizeConfigStore.set(root, fileConfig);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const viteConfig = fileConfig?.vite ?? {};
|
|
356
|
+
const compilerConfig = fileConfig?.compiler ?? {};
|
|
357
|
+
mergedOptions = {
|
|
358
|
+
...options,
|
|
359
|
+
ssr: options.ssr ?? compilerConfig.ssr ?? false,
|
|
360
|
+
sourceMap: options.sourceMap ?? compilerConfig.sourceMap,
|
|
361
|
+
vapor: options.vapor ?? compilerConfig.vapor ?? false,
|
|
362
|
+
include: options.include ?? viteConfig.include,
|
|
363
|
+
exclude: options.exclude ?? viteConfig.exclude,
|
|
364
|
+
scanPatterns: options.scanPatterns ?? viteConfig.scanPatterns,
|
|
365
|
+
ignorePatterns: options.ignorePatterns ?? viteConfig.ignorePatterns
|
|
366
|
+
};
|
|
367
|
+
filter = createFilter(mergedOptions.include, mergedOptions.exclude);
|
|
368
|
+
scanPatterns = mergedOptions.scanPatterns ?? ["**/*.vue"];
|
|
369
|
+
ignorePatterns = mergedOptions.ignorePatterns ?? [
|
|
370
|
+
"node_modules/**",
|
|
371
|
+
"dist/**",
|
|
372
|
+
".git/**"
|
|
373
|
+
];
|
|
374
|
+
},
|
|
375
|
+
configureServer(devServer) {
|
|
376
|
+
server = devServer;
|
|
377
|
+
},
|
|
378
|
+
async buildStart() {
|
|
379
|
+
await compileAll();
|
|
380
|
+
logger.log("Cache keys:", [...cache.keys()].slice(0, 3));
|
|
381
|
+
},
|
|
382
|
+
async resolveId(id, importer) {
|
|
383
|
+
if (id.startsWith("\0")) return null;
|
|
384
|
+
if (id.startsWith("vize:")) {
|
|
385
|
+
let realPath = id.slice(5);
|
|
386
|
+
if (realPath.endsWith(".ts")) realPath = realPath.slice(0, -3);
|
|
387
|
+
logger.log(`resolveId: redirecting stale vize: ID to ${realPath}`);
|
|
388
|
+
if (realPath.includes("node_modules")) return this.resolve(realPath, importer, { skipSelf: true });
|
|
389
|
+
return this.resolve(realPath, importer, { skipSelf: true });
|
|
390
|
+
}
|
|
391
|
+
if (id === VIRTUAL_CSS_MODULE) return RESOLVED_CSS_MODULE;
|
|
392
|
+
if (id.includes("?vue&type=style")) return id;
|
|
393
|
+
if (importer?.startsWith(VIRTUAL_PREFIX)) {
|
|
394
|
+
const realImporter = virtualToReal.get(importer) ?? importer.slice(VIRTUAL_PREFIX.length);
|
|
395
|
+
const cleanImporter = realImporter.endsWith(".ts") ? realImporter.slice(0, -3) : realImporter;
|
|
396
|
+
logger.log(`resolveId from virtual: id=${id}, cleanImporter=${cleanImporter}`);
|
|
397
|
+
if (id.startsWith("#")) try {
|
|
398
|
+
return await this.resolve(id, cleanImporter, { skipSelf: true });
|
|
399
|
+
} catch {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
if (!id.endsWith(".vue")) if (id.startsWith("./") || id.startsWith("../")) {
|
|
403
|
+
const [pathPart, queryPart] = id.split("?");
|
|
404
|
+
const querySuffix = queryPart ? `?${queryPart}` : "";
|
|
405
|
+
const resolved = path.resolve(path.dirname(cleanImporter), pathPart);
|
|
406
|
+
for (const ext of [
|
|
407
|
+
"",
|
|
408
|
+
".ts",
|
|
409
|
+
".tsx",
|
|
410
|
+
".js",
|
|
411
|
+
".jsx",
|
|
412
|
+
".json"
|
|
413
|
+
]) if (fs.existsSync(resolved + ext)) {
|
|
414
|
+
const finalPath = resolved + ext + querySuffix;
|
|
415
|
+
logger.log(`resolveId: resolved relative ${id} to ${finalPath}`);
|
|
416
|
+
return finalPath;
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
if (id.includes("/dist/") || id.includes("/lib/") || id.includes("/es/")) {
|
|
420
|
+
logger.log(`resolveId: skipping already-resolved path ${id}`);
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
logger.log(`resolveId: resolving external ${id} from ${cleanImporter}`);
|
|
424
|
+
const resolved = await this.resolve(id, cleanImporter, { skipSelf: true });
|
|
425
|
+
logger.log(`resolveId: resolved external ${id} to`, resolved?.id ?? "null");
|
|
426
|
+
return resolved;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (id.endsWith(".vue")) {
|
|
430
|
+
if (id.includes("node_modules")) {
|
|
431
|
+
logger.log(`resolveId: skipping node_modules import ${id}`);
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
const resolved = resolveVuePath(id, importer);
|
|
435
|
+
if (resolved.includes("node_modules")) {
|
|
436
|
+
logger.log(`resolveId: skipping node_modules path ${resolved}`);
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
if (!filter(resolved)) {
|
|
440
|
+
logger.log(`resolveId: skipping filtered path ${resolved}`);
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
const hasCache = cache.has(resolved);
|
|
444
|
+
const fileExists = fs.existsSync(resolved);
|
|
445
|
+
logger.log(`resolveId: id=${id}, resolved=${resolved}, hasCache=${hasCache}, fileExists=${fileExists}, importer=${importer ?? "none"}`);
|
|
446
|
+
if (hasCache || fileExists) {
|
|
447
|
+
const virtualId = VIRTUAL_PREFIX + resolved + ".ts";
|
|
448
|
+
virtualToReal.set(virtualId, resolved);
|
|
449
|
+
return virtualId;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
},
|
|
454
|
+
load(id) {
|
|
455
|
+
if (id === RESOLVED_CSS_MODULE) {
|
|
456
|
+
const allCss = Array.from(collectedCss.values()).join("\n\n");
|
|
457
|
+
return allCss;
|
|
458
|
+
}
|
|
459
|
+
if (id.includes("?vue&type=style")) {
|
|
460
|
+
const [filename] = id.split("?");
|
|
461
|
+
const realPath = filename.startsWith(VIRTUAL_PREFIX) ? virtualToReal.get(filename) ?? filename.slice(VIRTUAL_PREFIX.length) : filename;
|
|
462
|
+
const compiled = cache.get(realPath);
|
|
463
|
+
if (compiled?.css) return compiled.css;
|
|
464
|
+
return "";
|
|
465
|
+
}
|
|
466
|
+
if (id.startsWith(VIRTUAL_PREFIX)) {
|
|
467
|
+
const lookupId = id.endsWith(".ts") ? id.slice(0, -3) : id;
|
|
468
|
+
const realPath = virtualToReal.get(id) ?? lookupId.slice(VIRTUAL_PREFIX.length);
|
|
469
|
+
const compiled = cache.get(realPath);
|
|
470
|
+
if (compiled) {
|
|
471
|
+
const output = generateOutput(compiled, {
|
|
472
|
+
isProduction,
|
|
473
|
+
isDev: server !== null,
|
|
474
|
+
extractCss
|
|
475
|
+
});
|
|
476
|
+
return {
|
|
477
|
+
code: output,
|
|
478
|
+
map: null
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return null;
|
|
483
|
+
},
|
|
484
|
+
async transform(code, id) {
|
|
485
|
+
if (id.startsWith(VIRTUAL_PREFIX) && id.endsWith(".ts")) {
|
|
486
|
+
const result = await transformWithOxc(code, id.slice(VIRTUAL_PREFIX.length), { lang: "ts" });
|
|
487
|
+
return {
|
|
488
|
+
code: result.code,
|
|
489
|
+
map: result.map
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
return null;
|
|
493
|
+
},
|
|
494
|
+
async handleHotUpdate(ctx) {
|
|
495
|
+
const { file, server: server$1, read } = ctx;
|
|
496
|
+
if (file.endsWith(".vue") && filter(file)) try {
|
|
497
|
+
const source = await read();
|
|
498
|
+
const prevCompiled = cache.get(file);
|
|
499
|
+
compileFile(file, cache, {
|
|
500
|
+
sourceMap: mergedOptions.sourceMap ?? !isProduction,
|
|
501
|
+
ssr: mergedOptions.ssr ?? false
|
|
502
|
+
}, source);
|
|
503
|
+
const newCompiled = cache.get(file);
|
|
504
|
+
const updateType = detectHmrUpdateType(prevCompiled, newCompiled);
|
|
505
|
+
logger.log(`Re-compiled: ${path.relative(root, file)} (${updateType})`);
|
|
506
|
+
const virtualId = VIRTUAL_PREFIX + file + ".ts";
|
|
507
|
+
const modules = server$1.moduleGraph.getModulesByFile(virtualId) ?? server$1.moduleGraph.getModulesByFile(file);
|
|
508
|
+
if (updateType === "style-only" && newCompiled.css) {
|
|
509
|
+
server$1.ws.send({
|
|
510
|
+
type: "custom",
|
|
511
|
+
event: "vize:update",
|
|
512
|
+
data: {
|
|
513
|
+
id: newCompiled.scopeId,
|
|
514
|
+
type: "style-only",
|
|
515
|
+
css: newCompiled.css
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
return [];
|
|
519
|
+
}
|
|
520
|
+
if (modules) return [...modules];
|
|
521
|
+
} catch (e) {
|
|
522
|
+
logger.error(`Re-compilation failed for ${file}:`, e);
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
generateBundle(_, _bundle) {
|
|
526
|
+
if (!extractCss || collectedCss.size === 0) return;
|
|
527
|
+
const allCss = Array.from(collectedCss.values()).join("\n\n");
|
|
528
|
+
if (allCss.trim()) {
|
|
529
|
+
this.emitFile({
|
|
530
|
+
type: "asset",
|
|
531
|
+
fileName: "assets/vize-components.css",
|
|
532
|
+
source: allCss
|
|
533
|
+
});
|
|
534
|
+
logger.log(`Extracted CSS to assets/vize-components.css (${collectedCss.size} components)`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
var src_default = vize;
|
|
540
|
+
|
|
541
|
+
//#endregion
|
|
542
|
+
export { src_default as default, defineConfig, loadConfig, vize, vizeConfigStore };
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vizejs/vite-plugin",
|
|
3
|
+
"version": "0.0.1-alpha.100",
|
|
4
|
+
"description": "High-performance native Vite plugin for Vue SFC compilation powered by Vize",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"vite",
|
|
22
|
+
"vue",
|
|
23
|
+
"plugin",
|
|
24
|
+
"sfc",
|
|
25
|
+
"compiler",
|
|
26
|
+
"native",
|
|
27
|
+
"fast"
|
|
28
|
+
],
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/ubugeeei/vize",
|
|
32
|
+
"directory": "npm/vite-plugin-vize"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^22.0.0",
|
|
37
|
+
"tsdown": "^0.9.0",
|
|
38
|
+
"typescript": "~5.6.0",
|
|
39
|
+
"vite": "^8.0.0-beta.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"tinyglobby": "^0.2.0",
|
|
46
|
+
"@vizejs/native": "0.0.1-alpha.100"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsdown",
|
|
50
|
+
"dev": "tsdown --watch",
|
|
51
|
+
"lint": "oxlint --deny-warnings --type-aware --tsconfig tsconfig.json",
|
|
52
|
+
"lint:fix": "oxlint --type-aware --tsconfig tsconfig.json --fix",
|
|
53
|
+
"fmt": "oxfmt --write src",
|
|
54
|
+
"fmt:check": "oxfmt src"
|
|
55
|
+
}
|
|
56
|
+
}
|