@vizejs/vite-plugin 0.0.1-alpha.73 → 0.0.1-alpha.9

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 CHANGED
@@ -30,11 +30,11 @@ yarn add @vizejs/vite-plugin
30
30
  ```ts
31
31
  // vite.config.ts
32
32
  import { defineConfig } from 'vite'
33
- import vize from '@vizejs/vite-plugin'
33
+ import { vizeNative } from '@vizejs/vite-plugin'
34
34
 
35
35
  export default defineConfig({
36
36
  plugins: [
37
- vize({
37
+ vizeNative({
38
38
  // options
39
39
  })
40
40
  ]
@@ -47,12 +47,12 @@ For Nuxt 3, add the plugin to your `nuxt.config.ts`:
47
47
 
48
48
  ```ts
49
49
  // nuxt.config.ts
50
- import vize from '@vizejs/vite-plugin'
50
+ import { vizeNative } from '@vizejs/vite-plugin'
51
51
 
52
52
  export default defineNuxtConfig({
53
53
  vite: {
54
54
  plugins: [
55
- vize({
55
+ vizeNative({
56
56
  // Exclude Nuxt's internal .vue files if needed
57
57
  exclude: [/node_modules/, /#/, /\.nuxt/]
58
58
  })
@@ -81,7 +81,7 @@ export default defineNuxtConfig({
81
81
  },
82
82
  vite: {
83
83
  plugins: [
84
- vize()
84
+ vizeNative()
85
85
  ]
86
86
  }
87
87
  })
@@ -0,0 +1,6 @@
1
+ import type { CompileSfcFn, CompiledModule } from './types.js';
2
+ export declare function loadNative(): CompileSfcFn;
3
+ export declare function compileFile(filePath: string, cache: Map<string, CompiledModule>, options: {
4
+ sourceMap: boolean;
5
+ ssr: boolean;
6
+ }, source?: string): CompiledModule;
@@ -0,0 +1,46 @@
1
+ import fs from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { generateScopeId } from './utils.js';
4
+ const require = createRequire(import.meta.url);
5
+ let compileSfc = null;
6
+ export function loadNative() {
7
+ if (compileSfc)
8
+ return compileSfc;
9
+ try {
10
+ const native = require('@vizejs/native');
11
+ compileSfc = native.compileSfc;
12
+ return compileSfc;
13
+ }
14
+ catch (e) {
15
+ throw new Error(`Failed to load @vizejs/native. Make sure it's installed and built:\n${e}`);
16
+ }
17
+ }
18
+ export function compileFile(filePath, cache, options, source) {
19
+ const compile = loadNative();
20
+ const content = source ?? fs.readFileSync(filePath, 'utf-8');
21
+ const scopeId = generateScopeId(filePath);
22
+ const hasScoped = /<style[^>]*\bscoped\b/.test(content);
23
+ const result = compile(content, {
24
+ filename: filePath,
25
+ sourceMap: options.sourceMap,
26
+ ssr: options.ssr,
27
+ scopeId: hasScoped ? `data-v-${scopeId}` : undefined,
28
+ });
29
+ if (result.errors.length > 0) {
30
+ const errorMsg = result.errors.join('\n');
31
+ console.error(`[vize] Compilation error in ${filePath}:\n${errorMsg}`);
32
+ }
33
+ if (result.warnings.length > 0) {
34
+ result.warnings.forEach((warning) => {
35
+ console.warn(`[vize] Warning in ${filePath}: ${warning}`);
36
+ });
37
+ }
38
+ const compiled = {
39
+ code: result.code,
40
+ css: result.css,
41
+ scopeId,
42
+ hasScoped,
43
+ };
44
+ cache.set(filePath, compiled);
45
+ return compiled;
46
+ }
package/dist/index.d.ts CHANGED
@@ -1,170 +1,5 @@
1
- import { Plugin } from "vite";
2
-
3
- //#region src/types.d.ts
4
-
5
- interface VizeOptions {
6
- /**
7
- * Files to include in compilation
8
- * @default /\.vue$/
9
- */
10
- include?: string | RegExp | (string | RegExp)[];
11
- /**
12
- * Files to exclude from compilation
13
- * @default /node_modules/
14
- */
15
- exclude?: string | RegExp | (string | RegExp)[];
16
- /**
17
- * Force production mode
18
- * @default auto-detected from Vite config
19
- */
20
- isProduction?: boolean;
21
- /**
22
- * Enable SSR mode
23
- * @default false
24
- */
25
- ssr?: boolean;
26
- /**
27
- * Enable source map generation
28
- * @default true in development, false in production
29
- */
30
- sourceMap?: boolean;
31
- /**
32
- * Enable Vapor mode compilation
33
- * @default false
34
- */
35
- vapor?: boolean;
36
- /**
37
- * Root directory to scan for .vue files
38
- * @default Vite's root
39
- */
40
- root?: string;
41
- /**
42
- * Glob patterns to scan for .vue files during pre-compilation
43
- * @default ['**\/*.vue']
44
- */
45
- scanPatterns?: string[];
46
- /**
47
- * Glob patterns to ignore during pre-compilation
48
- * @default ['node_modules/**', 'dist/**', '.git/**']
49
- */
50
- ignorePatterns?: string[];
51
- /**
52
- * Config file search mode
53
- * - 'root': Search only in the project root directory
54
- * - 'auto': Search from cwd upward until finding a config file
55
- * - false: Disable config file loading
56
- * @default 'root'
57
- */
58
- configMode?: "root" | "auto" | false;
59
- /**
60
- * Custom config file path (overrides automatic search)
61
- */
62
- configFile?: string;
63
- /**
64
- * Enable debug logging
65
- * @default false
66
- */
67
- debug?: boolean;
68
- }
69
- interface CompiledModule {
70
- code: string;
71
- css?: string;
72
- scopeId: string;
73
- hasScoped: boolean;
74
- templateHash?: string;
75
- styleHash?: string;
76
- scriptHash?: string;
77
- }
78
- /**
79
- * Vize configuration options
80
- */
81
- interface VizeConfig {
82
- /**
83
- * Vue compiler options
84
- */
85
- compiler?: {
86
- /**
87
- * Enable Vapor mode compilation
88
- * @default false
89
- */
90
- vapor?: boolean;
91
- /**
92
- * Enable SSR mode
93
- * @default false
94
- */
95
- ssr?: boolean;
96
- /**
97
- * Enable source map generation
98
- * @default true in development, false in production
99
- */
100
- sourceMap?: boolean;
101
- };
102
- /**
103
- * Vite plugin options
104
- */
105
- vite?: {
106
- /**
107
- * Files to include in compilation
108
- * @default /\.vue$/
109
- */
110
- include?: string | RegExp | (string | RegExp)[];
111
- /**
112
- * Files to exclude from compilation
113
- * @default /node_modules/
114
- */
115
- exclude?: string | RegExp | (string | RegExp)[];
116
- /**
117
- * Glob patterns to scan for .vue files during pre-compilation
118
- * @default ['**\/*.vue']
119
- */
120
- scanPatterns?: string[];
121
- /**
122
- * Glob patterns to ignore during pre-compilation
123
- * @default ['node_modules/**', 'dist/**', '.git/**']
124
- */
125
- ignorePatterns?: string[];
126
- };
127
- /**
128
- * Linter options
129
- */
130
- linter?: {
131
- /**
132
- * Enable linting
133
- */
134
- enabled?: boolean;
135
- /**
136
- * Rules to enable/disable
137
- */
138
- rules?: Record<string, "off" | "warn" | "error">;
139
- };
140
- }
141
- /**
142
- * Options for loading vize.config file
143
- */
144
- interface LoadConfigOptions {
145
- /**
146
- * Config file search mode
147
- * - 'root': Search only in the specified root directory
148
- * - 'auto': Search from cwd upward until finding a config file
149
- * - 'none': Don't load config file
150
- * @default 'root'
151
- */
152
- mode?: "root" | "auto" | "none";
153
- /**
154
- * Custom config file path (overrides automatic search)
155
- */
156
- configFile?: string;
157
- } //#endregion
158
- //#region src/index.d.ts
159
- /**
160
- * Define a Vize configuration with type checking
161
- */
162
- declare function defineConfig(config: VizeConfig): VizeConfig;
163
- /**
164
- * Load Vize configuration from file
165
- */
166
- declare function loadConfig(root: string, options?: LoadConfigOptions): Promise<VizeConfig | null>;
167
- declare function vize(options?: VizeOptions): Plugin;
168
-
169
- //#endregion
170
- export { CompiledModule, LoadConfigOptions, VizeConfig, VizeOptions, vize as default, defineConfig, loadConfig, vize };
1
+ import type { Plugin } from 'vite';
2
+ import type { VizeOptions, CompiledModule } from './types.js';
3
+ export type { VizeOptions, CompiledModule };
4
+ export declare function vize(options?: VizeOptions): Plugin;
5
+ export default vize;
package/dist/index.js CHANGED
@@ -1,495 +1,141 @@
1
- import path from "node:path";
2
- import fs from "node:fs";
3
- import { glob } from "tinyglobby";
4
- import * as native from "@vizejs/native";
5
- import { createHash } from "node:crypto";
6
-
7
- //#region src/hmr.ts
8
- /**
9
- * Detect the type of HMR update needed based on content hash changes.
10
- *
11
- * @param prev - Previously compiled module (undefined if first compile)
12
- * @param next - Newly compiled module
13
- * @returns The type of HMR update needed
14
- */
15
- function detectHmrUpdateType(prev, next) {
16
- if (!prev) return "full-reload";
17
- const scriptChanged = prev.scriptHash !== next.scriptHash;
18
- if (scriptChanged) return "full-reload";
19
- const templateChanged = prev.templateHash !== next.templateHash;
20
- const styleChanged = prev.styleHash !== next.styleHash;
21
- if (styleChanged && !templateChanged) return "style-only";
22
- if (templateChanged) return "template-only";
23
- return "full-reload";
24
- }
25
- /**
26
- * Generate HMR-aware code output based on update type.
27
- */
28
- function generateHmrCode(scopeId, updateType) {
29
- return `
30
- if (import.meta.hot) {
31
- _sfc_main.__hmrId = ${JSON.stringify(scopeId)};
32
- _sfc_main.__hmrUpdateType = ${JSON.stringify(updateType)};
33
-
34
- import.meta.hot.accept((mod) => {
35
- if (!mod) return;
36
- const { default: updated } = mod;
37
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
38
- const updateType = updated.__hmrUpdateType || 'full-reload';
39
- if (updateType === 'template-only') {
40
- __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render);
41
- } else {
42
- __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated);
43
- }
44
- }
45
- });
46
-
47
- import.meta.hot.on('vize:update', (data) => {
48
- if (data.id !== _sfc_main.__hmrId) return;
49
-
50
- if (data.type === 'style-only') {
51
- // Update styles without remounting component
52
- const styleId = 'vize-style-' + _sfc_main.__hmrId;
53
- const styleEl = document.getElementById(styleId);
54
- if (styleEl && data.css) {
55
- styleEl.textContent = data.css;
56
- }
1
+ import path from 'node:path';
2
+ import { glob } from 'tinyglobby';
3
+ import { compileFile } from './compiler.js';
4
+ import { createFilter, generateOutput } from './utils.js';
5
+ const VIRTUAL_PREFIX = '\0vize:';
6
+ export function vize(options = {}) {
7
+ const filter = createFilter(options.include, options.exclude);
8
+ const cache = new Map();
9
+ // Map from virtual ID to real file path
10
+ const virtualToReal = new Map();
11
+ let isProduction;
12
+ let root;
13
+ let server = null;
14
+ const scanPatterns = options.scanPatterns ?? ['**/*.vue'];
15
+ const ignorePatterns = options.ignorePatterns ?? [
16
+ 'node_modules/**',
17
+ 'dist/**',
18
+ '.git/**',
19
+ ];
20
+ async function compileAll() {
21
+ const startTime = performance.now();
22
+ const files = await glob(scanPatterns, {
23
+ cwd: root,
24
+ ignore: ignorePatterns,
25
+ absolute: true,
26
+ });
27
+ console.log(`[vize] Pre-compiling ${files.length} Vue files...`);
28
+ let successCount = 0;
29
+ let errorCount = 0;
30
+ for (const file of files) {
31
+ try {
32
+ compileFile(file, cache, {
33
+ sourceMap: options.sourceMap ?? !isProduction,
34
+ ssr: options.ssr ?? false,
35
+ });
36
+ successCount++;
37
+ }
38
+ catch (e) {
39
+ errorCount++;
40
+ console.error(`[vize] Failed to compile ${file}:`, e);
41
+ }
42
+ }
43
+ const elapsed = (performance.now() - startTime).toFixed(2);
44
+ console.log(`[vize] Pre-compilation complete: ${successCount} succeeded, ${errorCount} failed (${elapsed}ms)`);
57
45
  }
58
- });
59
-
60
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
61
- __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main);
62
- }
63
- }`;
64
- }
65
-
66
- //#endregion
67
- //#region src/utils.ts
68
- function generateScopeId(filename) {
69
- const hash = createHash("sha256").update(filename).digest("hex");
70
- return hash.slice(0, 8);
71
- }
72
- function createFilter(include, exclude) {
73
- const includePatterns = include ? Array.isArray(include) ? include : [include] : [/\.vue$/];
74
- const excludePatterns = exclude ? Array.isArray(exclude) ? exclude : [exclude] : [/node_modules/];
75
- return (id) => {
76
- const matchInclude = includePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
77
- const matchExclude = excludePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
78
- return matchInclude && !matchExclude;
79
- };
80
- }
81
- function generateOutput(compiled, options) {
82
- const { isProduction, isDev, hmrUpdateType, extractCss } = options;
83
- let output = compiled.code;
84
- const exportDefaultRegex = /^export default /m;
85
- const hasExportDefault = exportDefaultRegex.test(output);
86
- const hasSfcMainDefined = /\bconst\s+_sfc_main\s*=/.test(output);
87
- if (hasExportDefault && !hasSfcMainDefined) {
88
- output = output.replace(exportDefaultRegex, "const _sfc_main = ");
89
- if (compiled.hasScoped && compiled.scopeId) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
90
- output += "\nexport default _sfc_main;";
91
- } else if (hasExportDefault && hasSfcMainDefined) {
92
- if (compiled.hasScoped && compiled.scopeId) output = output.replace(/^export default _sfc_main/m, `_sfc_main.__scopeId = "data-v-${compiled.scopeId}";\nexport default _sfc_main`);
93
- }
94
- if (compiled.css && !(isProduction && extractCss)) {
95
- const cssCode = JSON.stringify(compiled.css);
96
- const cssId = JSON.stringify(`vize-style-${compiled.scopeId}`);
97
- output = `
98
- const __vize_css__ = ${cssCode};
99
- const __vize_css_id__ = ${cssId};
100
- (function() {
101
- if (typeof document !== 'undefined') {
102
- let style = document.getElementById(__vize_css_id__);
103
- if (!style) {
104
- style = document.createElement('style');
105
- style.id = __vize_css_id__;
106
- style.textContent = __vize_css__;
107
- document.head.appendChild(style);
108
- } else {
109
- style.textContent = __vize_css__;
46
+ function resolveVuePath(id, importer) {
47
+ let resolved;
48
+ if (path.isAbsolute(id)) {
49
+ resolved = id;
50
+ }
51
+ else if (importer) {
52
+ // Remove virtual prefix from importer if present
53
+ const realImporter = importer.startsWith(VIRTUAL_PREFIX)
54
+ ? virtualToReal.get(importer) ?? importer.slice(VIRTUAL_PREFIX.length)
55
+ : importer;
56
+ resolved = path.resolve(path.dirname(realImporter), id);
57
+ }
58
+ else {
59
+ resolved = path.resolve(root, id);
60
+ }
61
+ return path.normalize(resolved);
110
62
  }
111
- }
112
- })();
113
- ${output}`;
114
- }
115
- if (!isProduction && isDev && hasExportDefault) output += generateHmrCode(compiled.scopeId, hmrUpdateType ?? "full-reload");
116
- return output;
117
- }
118
-
119
- //#endregion
120
- //#region src/compiler.ts
121
- const { compileSfc, compileSfcBatchWithResults } = native;
122
- function compileFile(filePath, cache, options, source) {
123
- const content = source ?? fs.readFileSync(filePath, "utf-8");
124
- const scopeId = generateScopeId(filePath);
125
- const hasScoped = /<style[^>]*\bscoped\b/.test(content);
126
- const result = compileSfc(content, {
127
- filename: filePath,
128
- sourceMap: options.sourceMap,
129
- ssr: options.ssr,
130
- scopeId: hasScoped ? `data-v-${scopeId}` : void 0
131
- });
132
- if (result.errors.length > 0) {
133
- const errorMsg = result.errors.join("\n");
134
- console.error(`[vize] Compilation error in ${filePath}:\n${errorMsg}`);
135
- }
136
- if (result.warnings.length > 0) result.warnings.forEach((warning) => {
137
- console.warn(`[vize] Warning in ${filePath}: ${warning}`);
138
- });
139
- const compiled = {
140
- code: result.code,
141
- css: result.css,
142
- scopeId,
143
- hasScoped
144
- };
145
- cache.set(filePath, compiled);
146
- return compiled;
147
- }
148
- /**
149
- * Batch compile multiple files in parallel using native Rust multithreading.
150
- * Returns per-file results with content hashes for HMR.
151
- */
152
- function compileBatch(files, cache, options) {
153
- const inputs = files.map((f) => ({
154
- path: f.path,
155
- source: f.source
156
- }));
157
- const result = compileSfcBatchWithResults(inputs, { ssr: options.ssr });
158
- for (const fileResult of result.results) {
159
- if (fileResult.errors.length === 0) cache.set(fileResult.path, {
160
- code: fileResult.code,
161
- css: fileResult.css,
162
- scopeId: fileResult.scopeId,
163
- hasScoped: fileResult.hasScoped,
164
- templateHash: fileResult.templateHash,
165
- styleHash: fileResult.styleHash,
166
- scriptHash: fileResult.scriptHash
167
- });
168
- if (fileResult.errors.length > 0) console.error(`[vize] Compilation error in ${fileResult.path}:\n${fileResult.errors.join("\n")}`);
169
- if (fileResult.warnings.length > 0) fileResult.warnings.forEach((warning) => {
170
- console.warn(`[vize] Warning in ${fileResult.path}: ${warning}`);
171
- });
172
- }
173
- return result;
174
- }
175
-
176
- //#endregion
177
- //#region src/index.ts
178
- const CONFIG_FILES = [
179
- "vize.config.ts",
180
- "vize.config.js",
181
- "vize.config.mjs",
182
- "vize.config.cjs",
183
- "vize.config.json"
184
- ];
185
- /**
186
- * Define a Vize configuration with type checking
187
- */
188
- function defineConfig(config) {
189
- return config;
190
- }
191
- /**
192
- * Load Vize configuration from file
193
- */
194
- async function loadConfig(root, options = {}) {
195
- const { mode = "root", configFile } = options;
196
- if (mode === "none") return null;
197
- const searchMode = mode === "auto" ? "nearest" : mode;
198
- if (configFile) {
199
- const configPath = path.isAbsolute(configFile) ? configFile : path.resolve(root, configFile);
200
- return loadConfigFile(configPath);
201
- }
202
- let searchDir = root;
203
- while (true) {
204
- for (const filename of CONFIG_FILES) {
205
- const configPath = path.join(searchDir, filename);
206
- if (fs.existsSync(configPath)) return loadConfigFile(configPath);
207
- }
208
- if (searchMode === "root") break;
209
- const parentDir = path.dirname(searchDir);
210
- if (parentDir === searchDir) break;
211
- searchDir = parentDir;
212
- }
213
- return null;
214
- }
215
- async function loadConfigFile(configPath) {
216
- if (!fs.existsSync(configPath)) return null;
217
- const ext = path.extname(configPath);
218
- if (ext === ".json") {
219
- const content = fs.readFileSync(configPath, "utf-8");
220
- return JSON.parse(content);
221
- }
222
- try {
223
- const module = await import(configPath);
224
- return module.default ?? module;
225
- } catch (e) {
226
- console.warn(`[vize] Failed to load config from ${configPath}:`, e);
227
- return null;
228
- }
229
- }
230
- const VIRTUAL_PREFIX = "\0vize:";
231
- const VIRTUAL_CSS_MODULE = "virtual:vize-styles";
232
- const RESOLVED_CSS_MODULE = "\0vize:all-styles.css";
233
- function createLogger(debug) {
234
- return {
235
- log: (...args) => debug && console.log("[vize]", ...args),
236
- info: (...args) => console.log("[vize]", ...args),
237
- warn: (...args) => console.warn("[vize]", ...args),
238
- error: (...args) => console.error("[vize]", ...args)
239
- };
240
- }
241
- function vize(options = {}) {
242
- const cache = new Map();
243
- const virtualToReal = new Map();
244
- const collectedCss = new Map();
245
- let isProduction;
246
- let root;
247
- let server = null;
248
- let filter;
249
- let scanPatterns;
250
- let ignorePatterns;
251
- let mergedOptions;
252
- let extractCss = false;
253
- const logger = createLogger(options.debug ?? false);
254
- async function compileAll() {
255
- const startTime = performance.now();
256
- const files = await glob(scanPatterns, {
257
- cwd: root,
258
- ignore: ignorePatterns,
259
- absolute: true
260
- });
261
- logger.info(`Pre-compiling ${files.length} Vue files...`);
262
- const fileContents = [];
263
- for (const file of files) try {
264
- const source = fs.readFileSync(file, "utf-8");
265
- fileContents.push({
266
- path: file,
267
- source
268
- });
269
- } catch (e) {
270
- logger.error(`Failed to read ${file}:`, e);
271
- }
272
- const result = compileBatch(fileContents, cache, { ssr: mergedOptions.ssr ?? false });
273
- if (isProduction) {
274
- for (const fileResult of result.results) if (fileResult.css) collectedCss.set(fileResult.path, fileResult.css);
275
- }
276
- const elapsed = (performance.now() - startTime).toFixed(2);
277
- logger.info(`Pre-compilation complete: ${result.successCount} succeeded, ${result.failedCount} failed (${elapsed}ms, native batch: ${result.timeMs.toFixed(2)}ms)`);
278
- }
279
- function resolveVuePath(id, importer) {
280
- let resolved;
281
- if (id.startsWith("/@fs/")) resolved = id.slice(4);
282
- else if (id.startsWith("/") && !fs.existsSync(id)) resolved = path.resolve(root, id.slice(1));
283
- else if (path.isAbsolute(id)) resolved = id;
284
- else if (importer) {
285
- let realImporter = importer.startsWith(VIRTUAL_PREFIX) ? virtualToReal.get(importer) ?? importer.slice(VIRTUAL_PREFIX.length) : importer;
286
- if (realImporter.endsWith(".vue.ts")) realImporter = realImporter.slice(0, -3);
287
- resolved = path.resolve(path.dirname(realImporter), id);
288
- } else resolved = path.resolve(root, id);
289
- if (!path.isAbsolute(resolved)) resolved = path.resolve(root, resolved);
290
- return path.normalize(resolved);
291
- }
292
- return {
293
- name: "vite-plugin-vize",
294
- enforce: "pre",
295
- config() {
296
- return { optimizeDeps: {
297
- include: ["vue"],
298
- exclude: ["virtual:vize-styles"],
299
- esbuildOptions: { plugins: [{
300
- name: "vize-externalize-vue",
301
- setup(build) {
302
- build.onResolve({ filter: /\.vue$/ }, (args) => ({
303
- path: args.path,
304
- external: true
305
- }));
306
- }
307
- }] },
308
- rolldownOptions: { external: [/\.vue$/] }
309
- } };
310
- },
311
- async configResolved(resolvedConfig) {
312
- root = options.root ?? resolvedConfig.root;
313
- isProduction = options.isProduction ?? resolvedConfig.isProduction;
314
- extractCss = isProduction;
315
- let fileConfig = null;
316
- if (options.configMode !== false) {
317
- fileConfig = await loadConfig(root, {
318
- mode: options.configMode ?? "root",
319
- configFile: options.configFile
320
- });
321
- if (fileConfig) logger.log("Loaded config from vize.config file");
322
- }
323
- const viteConfig = fileConfig?.vite ?? {};
324
- const compilerConfig = fileConfig?.compiler ?? {};
325
- mergedOptions = {
326
- ...options,
327
- ssr: options.ssr ?? compilerConfig.ssr ?? false,
328
- sourceMap: options.sourceMap ?? compilerConfig.sourceMap,
329
- vapor: options.vapor ?? compilerConfig.vapor ?? false,
330
- include: options.include ?? viteConfig.include,
331
- exclude: options.exclude ?? viteConfig.exclude,
332
- scanPatterns: options.scanPatterns ?? viteConfig.scanPatterns,
333
- ignorePatterns: options.ignorePatterns ?? viteConfig.ignorePatterns
334
- };
335
- filter = createFilter(mergedOptions.include, mergedOptions.exclude);
336
- scanPatterns = mergedOptions.scanPatterns ?? ["**/*.vue"];
337
- ignorePatterns = mergedOptions.ignorePatterns ?? [
338
- "node_modules/**",
339
- "dist/**",
340
- ".git/**"
341
- ];
342
- },
343
- configureServer(devServer) {
344
- server = devServer;
345
- },
346
- async buildStart() {
347
- await compileAll();
348
- logger.log("Cache keys:", [...cache.keys()].slice(0, 3));
349
- },
350
- async resolveId(id, importer) {
351
- if (id.startsWith("\0")) return null;
352
- if (id.startsWith("vize:")) {
353
- let realPath = id.slice(5);
354
- if (realPath.endsWith(".ts")) realPath = realPath.slice(0, -3);
355
- logger.log(`resolveId: redirecting stale vize: ID to ${realPath}`);
356
- if (realPath.includes("node_modules")) return realPath;
357
- return this.resolve(realPath, importer, { skipSelf: true });
358
- }
359
- if (id === VIRTUAL_CSS_MODULE) return RESOLVED_CSS_MODULE;
360
- if (id.includes("?vue&type=style")) return id;
361
- if (importer?.startsWith(VIRTUAL_PREFIX)) {
362
- const realImporter = virtualToReal.get(importer) ?? importer.slice(VIRTUAL_PREFIX.length);
363
- const cleanImporter = realImporter.endsWith(".ts") ? realImporter.slice(0, -3) : realImporter;
364
- logger.log(`resolveId from virtual: id=${id}, cleanImporter=${cleanImporter}`);
365
- if (!id.endsWith(".vue")) if (id.startsWith("./") || id.startsWith("../")) {
366
- const [pathPart, queryPart] = id.split("?");
367
- const querySuffix = queryPart ? `?${queryPart}` : "";
368
- const resolved = path.resolve(path.dirname(cleanImporter), pathPart);
369
- for (const ext of [
370
- "",
371
- ".ts",
372
- ".tsx",
373
- ".js",
374
- ".jsx",
375
- ".json"
376
- ]) if (fs.existsSync(resolved + ext)) {
377
- const finalPath = resolved + ext + querySuffix;
378
- logger.log(`resolveId: resolved relative ${id} to ${finalPath}`);
379
- return finalPath;
380
- }
381
- } else {
382
- if (id.includes("/dist/") || id.includes("/lib/") || id.includes("/es/")) {
383
- logger.log(`resolveId: skipping already-resolved path ${id}`);
384
- return null;
385
- }
386
- logger.log(`resolveId: resolving external ${id} from ${cleanImporter}`);
387
- const resolved = await this.resolve(id, cleanImporter, { skipSelf: true });
388
- logger.log(`resolveId: resolved external ${id} to`, resolved?.id ?? "null");
389
- return resolved;
390
- }
391
- }
392
- if (id.endsWith(".vue")) {
393
- if (id.includes("node_modules")) {
394
- logger.log(`resolveId: skipping node_modules import ${id}`);
395
- return null;
396
- }
397
- const resolved = resolveVuePath(id, importer);
398
- if (resolved.includes("node_modules")) {
399
- logger.log(`resolveId: skipping node_modules path ${resolved}`);
400
- return null;
401
- }
402
- if (!filter(resolved)) {
403
- logger.log(`resolveId: skipping filtered path ${resolved}`);
404
- return null;
405
- }
406
- const hasCache = cache.has(resolved);
407
- const fileExists = fs.existsSync(resolved);
408
- logger.log(`resolveId: id=${id}, resolved=${resolved}, hasCache=${hasCache}, fileExists=${fileExists}, importer=${importer ?? "none"}`);
409
- if (hasCache || fileExists) {
410
- const virtualId = VIRTUAL_PREFIX + resolved + ".ts";
411
- virtualToReal.set(virtualId, resolved);
412
- return virtualId;
413
- }
414
- }
415
- return null;
416
- },
417
- load(id) {
418
- if (id === RESOLVED_CSS_MODULE) {
419
- const allCss = Array.from(collectedCss.values()).join("\n\n");
420
- return allCss;
421
- }
422
- if (id.includes("?vue&type=style")) {
423
- const [filename] = id.split("?");
424
- const realPath = filename.startsWith(VIRTUAL_PREFIX) ? virtualToReal.get(filename) ?? filename.slice(VIRTUAL_PREFIX.length) : filename;
425
- const compiled = cache.get(realPath);
426
- if (compiled?.css) return compiled.css;
427
- return "";
428
- }
429
- if (id.startsWith(VIRTUAL_PREFIX)) {
430
- const lookupId = id.endsWith(".ts") ? id.slice(0, -3) : id;
431
- const realPath = virtualToReal.get(id) ?? lookupId.slice(VIRTUAL_PREFIX.length);
432
- const compiled = cache.get(realPath);
433
- if (compiled) {
434
- const output = generateOutput(compiled, {
435
- isProduction,
436
- isDev: server !== null,
437
- extractCss
438
- });
439
- return {
440
- code: output,
441
- map: null
442
- };
443
- }
444
- }
445
- return null;
446
- },
447
- async handleHotUpdate(ctx) {
448
- const { file, server: server$1, read } = ctx;
449
- if (file.endsWith(".vue") && filter(file)) try {
450
- const source = await read();
451
- const prevCompiled = cache.get(file);
452
- compileFile(file, cache, {
453
- sourceMap: mergedOptions.sourceMap ?? !isProduction,
454
- ssr: mergedOptions.ssr ?? false
455
- }, source);
456
- const newCompiled = cache.get(file);
457
- const updateType = detectHmrUpdateType(prevCompiled, newCompiled);
458
- logger.log(`Re-compiled: ${path.relative(root, file)} (${updateType})`);
459
- const virtualId = VIRTUAL_PREFIX + file + ".ts";
460
- const modules = server$1.moduleGraph.getModulesByFile(virtualId) ?? server$1.moduleGraph.getModulesByFile(file);
461
- if (updateType === "style-only" && newCompiled.css) {
462
- server$1.ws.send({
463
- type: "custom",
464
- event: "vize:update",
465
- data: {
466
- id: newCompiled.scopeId,
467
- type: "style-only",
468
- css: newCompiled.css
469
- }
470
- });
471
- return [];
472
- }
473
- if (modules) return [...modules];
474
- } catch (e) {
475
- logger.error(`Re-compilation failed for ${file}:`, e);
476
- }
477
- },
478
- generateBundle(_, _bundle) {
479
- if (!extractCss || collectedCss.size === 0) return;
480
- const allCss = Array.from(collectedCss.values()).join("\n\n");
481
- if (allCss.trim()) {
482
- this.emitFile({
483
- type: "asset",
484
- fileName: "assets/vize-components.css",
485
- source: allCss
486
- });
487
- logger.log(`Extracted CSS to assets/vize-components.css (${collectedCss.size} components)`);
488
- }
489
- }
490
- };
63
+ return {
64
+ name: 'vite-plugin-vize',
65
+ enforce: 'pre',
66
+ configResolved(resolvedConfig) {
67
+ isProduction = options.isProduction ?? resolvedConfig.isProduction;
68
+ root = options.root ?? resolvedConfig.root;
69
+ },
70
+ configureServer(devServer) {
71
+ server = devServer;
72
+ },
73
+ async buildStart() {
74
+ await compileAll();
75
+ },
76
+ resolveId(id, importer) {
77
+ if (id.includes('?vue&type=style')) {
78
+ return id;
79
+ }
80
+ if (id.endsWith('.vue')) {
81
+ const resolved = resolveVuePath(id, importer);
82
+ // Return virtual module ID if cached
83
+ if (cache.has(resolved)) {
84
+ const virtualId = VIRTUAL_PREFIX + resolved;
85
+ virtualToReal.set(virtualId, resolved);
86
+ return virtualId;
87
+ }
88
+ }
89
+ return null;
90
+ },
91
+ load(id) {
92
+ if (id.includes('?vue&type=style')) {
93
+ const [filename] = id.split('?');
94
+ const realPath = filename.startsWith(VIRTUAL_PREFIX)
95
+ ? virtualToReal.get(filename) ?? filename.slice(VIRTUAL_PREFIX.length)
96
+ : filename;
97
+ const compiled = cache.get(realPath);
98
+ if (compiled?.css) {
99
+ return compiled.css;
100
+ }
101
+ return '';
102
+ }
103
+ // Handle virtual module
104
+ if (id.startsWith(VIRTUAL_PREFIX)) {
105
+ const realPath = virtualToReal.get(id) ?? id.slice(VIRTUAL_PREFIX.length);
106
+ const compiled = cache.get(realPath);
107
+ if (compiled) {
108
+ return {
109
+ code: generateOutput(compiled, isProduction, server !== null),
110
+ map: null,
111
+ };
112
+ }
113
+ }
114
+ return null;
115
+ },
116
+ async handleHotUpdate(ctx) {
117
+ const { file, server, read } = ctx;
118
+ if (file.endsWith('.vue') && filter(file)) {
119
+ try {
120
+ const source = await read();
121
+ compileFile(file, cache, {
122
+ sourceMap: options.sourceMap ?? !isProduction,
123
+ ssr: options.ssr ?? false,
124
+ }, source);
125
+ console.log(`[vize] Re-compiled: ${path.relative(root, file)}`);
126
+ }
127
+ catch (e) {
128
+ console.error(`[vize] Re-compilation failed for ${file}:`, e);
129
+ }
130
+ // Find the virtual module for this file
131
+ const virtualId = VIRTUAL_PREFIX + file;
132
+ const modules = server.moduleGraph.getModulesByFile(virtualId)
133
+ ?? server.moduleGraph.getModulesByFile(file);
134
+ if (modules) {
135
+ return [...modules];
136
+ }
137
+ }
138
+ },
139
+ };
491
140
  }
492
- var src_default = vize;
493
-
494
- //#endregion
495
- export { src_default as default, defineConfig, loadConfig, vize };
141
+ export default vize;
@@ -0,0 +1,66 @@
1
+ export interface SfcCompileOptionsNapi {
2
+ filename?: string;
3
+ sourceMap?: boolean;
4
+ ssr?: boolean;
5
+ scopeId?: string;
6
+ }
7
+ export interface SfcCompileResultNapi {
8
+ code: string;
9
+ css?: string;
10
+ errors: string[];
11
+ warnings: string[];
12
+ }
13
+ export type CompileSfcFn = (source: string, options?: SfcCompileOptionsNapi) => SfcCompileResultNapi;
14
+ export interface VizeOptions {
15
+ /**
16
+ * Files to include in compilation
17
+ * @default /\.vue$/
18
+ */
19
+ include?: string | RegExp | (string | RegExp)[];
20
+ /**
21
+ * Files to exclude from compilation
22
+ * @default /node_modules/
23
+ */
24
+ exclude?: string | RegExp | (string | RegExp)[];
25
+ /**
26
+ * Force production mode
27
+ * @default auto-detected from Vite config
28
+ */
29
+ isProduction?: boolean;
30
+ /**
31
+ * Enable SSR mode
32
+ * @default false
33
+ */
34
+ ssr?: boolean;
35
+ /**
36
+ * Enable source map generation
37
+ * @default true in development, false in production
38
+ */
39
+ sourceMap?: boolean;
40
+ /**
41
+ * Enable Vapor mode compilation
42
+ * @default false
43
+ */
44
+ vapor?: boolean;
45
+ /**
46
+ * Root directory to scan for .vue files
47
+ * @default Vite's root
48
+ */
49
+ root?: string;
50
+ /**
51
+ * Glob patterns to scan for .vue files during pre-compilation
52
+ * @default ['**\/*.vue']
53
+ */
54
+ scanPatterns?: string[];
55
+ /**
56
+ * Glob patterns to ignore during pre-compilation
57
+ * @default ['node_modules/**', 'dist/**', '.git/**']
58
+ */
59
+ ignorePatterns?: string[];
60
+ }
61
+ export interface CompiledModule {
62
+ code: string;
63
+ css?: string;
64
+ scopeId: string;
65
+ hasScoped: boolean;
66
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { CompiledModule } from './types.js';
2
+ export declare function generateScopeId(filename: string): string;
3
+ export declare function createFilter(include?: string | RegExp | (string | RegExp)[], exclude?: string | RegExp | (string | RegExp)[]): (id: string) => boolean;
4
+ export declare function generateOutput(compiled: CompiledModule, isProduction: boolean, isDev: boolean): string;
package/dist/utils.js ADDED
@@ -0,0 +1,71 @@
1
+ import { createHash } from 'node:crypto';
2
+ export function generateScopeId(filename) {
3
+ const hash = createHash('sha256').update(filename).digest('hex');
4
+ return hash.slice(0, 8);
5
+ }
6
+ export function createFilter(include, exclude) {
7
+ const includePatterns = include
8
+ ? Array.isArray(include)
9
+ ? include
10
+ : [include]
11
+ : [/\.vue$/];
12
+ const excludePatterns = exclude
13
+ ? Array.isArray(exclude)
14
+ ? exclude
15
+ : [exclude]
16
+ : [/node_modules/];
17
+ return (id) => {
18
+ const matchInclude = includePatterns.some((pattern) => typeof pattern === 'string' ? id.includes(pattern) : pattern.test(id));
19
+ const matchExclude = excludePatterns.some((pattern) => typeof pattern === 'string' ? id.includes(pattern) : pattern.test(id));
20
+ return matchInclude && !matchExclude;
21
+ };
22
+ }
23
+ export function generateOutput(compiled, isProduction, isDev) {
24
+ let output = compiled.code;
25
+ // Rewrite "export default" to named variable for HMR
26
+ const hasExportDefault = output.includes('export default');
27
+ if (hasExportDefault) {
28
+ output = output.replace('export default', 'const _sfc_main =');
29
+ output += '\nexport default _sfc_main;';
30
+ }
31
+ // Inject CSS
32
+ if (compiled.css) {
33
+ const cssCode = JSON.stringify(compiled.css);
34
+ const cssId = JSON.stringify(`vize-style-${compiled.scopeId}`);
35
+ output = `
36
+ const __vize_css__ = ${cssCode};
37
+ const __vize_css_id__ = ${cssId};
38
+ (function() {
39
+ if (typeof document !== 'undefined') {
40
+ let style = document.getElementById(__vize_css_id__);
41
+ if (!style) {
42
+ style = document.createElement('style');
43
+ style.id = __vize_css_id__;
44
+ style.textContent = __vize_css__;
45
+ document.head.appendChild(style);
46
+ } else {
47
+ style.textContent = __vize_css__;
48
+ }
49
+ }
50
+ })();
51
+ ${output}`;
52
+ }
53
+ // Add HMR support in development
54
+ if (!isProduction && isDev && hasExportDefault) {
55
+ output += `
56
+ if (import.meta.hot) {
57
+ _sfc_main.__hmrId = ${JSON.stringify(compiled.scopeId)};
58
+ import.meta.hot.accept((mod) => {
59
+ if (!mod) return;
60
+ const { default: updated } = mod;
61
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
62
+ __VUE_HMR_RUNTIME__.reload(_sfc_main.__hmrId, updated);
63
+ }
64
+ });
65
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
66
+ __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main);
67
+ }
68
+ }`;
69
+ }
70
+ return output;
71
+ }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@vizejs/vite-plugin",
3
- "version": "0.0.1-alpha.73",
3
+ "version": "0.0.1-alpha.9",
4
4
  "description": "High-performance native Vite plugin for Vue SFC compilation powered by Vize",
5
5
  "publishConfig": {
6
- "provenance": true,
6
+ "provenance": false,
7
7
  "access": "public"
8
8
  },
9
9
  "type": "module",
@@ -15,6 +15,10 @@
15
15
  "types": "./dist/index.d.ts"
16
16
  }
17
17
  },
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsc --watch"
21
+ },
18
22
  "files": [
19
23
  "dist"
20
24
  ],
@@ -27,31 +31,15 @@
27
31
  "native",
28
32
  "fast"
29
33
  ],
30
- "repository": {
31
- "type": "git",
32
- "url": "https://github.com/ubugeeei/vize",
33
- "directory": "npm/vite-plugin-vize"
34
- },
35
34
  "license": "MIT",
36
35
  "devDependencies": {
37
36
  "@types/node": "^22.0.0",
38
- "tsdown": "^0.9.0",
37
+ "@vizejs/native": "workspace:*",
38
+ "tinyglobby": "^0.2.0",
39
39
  "typescript": "~5.6.0",
40
- "vite": "^8.0.0-beta.0"
40
+ "vite": "^7.3.1"
41
41
  },
42
42
  "peerDependencies": {
43
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0"
44
- },
45
- "dependencies": {
46
- "tinyglobby": "^0.2.0",
47
- "@vizejs/native": "0.0.1-alpha.73"
48
- },
49
- "scripts": {
50
- "build": "tsdown",
51
- "dev": "tsdown --watch",
52
- "lint": "oxlint --deny-warnings --type-aware --tsconfig tsconfig.json",
53
- "lint:fix": "oxlint --type-aware --tsconfig tsconfig.json --fix",
54
- "fmt": "oxfmt --write src",
55
- "fmt:check": "oxfmt src"
43
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
56
44
  }
57
- }
45
+ }