@vizejs/unplugin 0.58.0 → 0.60.0

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
@@ -16,8 +16,10 @@ Rspack intentionally uses the dedicated `@vizejs/rspack-plugin` path instead of
16
16
 
17
17
  ## Installation
18
18
 
19
+ Install `vp` once from the [Vite+ install guide](https://viteplus.dev/guide/install), then add the package:
20
+
19
21
  ```bash
20
- npm install @vizejs/unplugin
22
+ vp install @vizejs/unplugin
21
23
  ```
22
24
 
23
25
  ## Usage
@@ -0,0 +1,7 @@
1
+ import { t as VizeUnpluginOptions } from "./types-o6z7QlYN.mjs";
2
+ import * as _$unplugin from "unplugin";
3
+
4
+ //#region src/esbuild.d.ts
5
+ declare const _default: (options?: VizeUnpluginOptions | undefined) => _$unplugin.EsbuildPlugin;
6
+ //#endregion
7
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as vizeUnplugin } from "./unplugin-8tCaeF-H.mjs";
2
+ //#region src/esbuild.ts
3
+ var esbuild_default = vizeUnplugin.esbuild;
4
+ //#endregion
5
+ export { esbuild_default as default };
@@ -0,0 +1,7 @@
1
+ import { t as VizeUnpluginOptions } from "./types-o6z7QlYN.mjs";
2
+ import * as _$unplugin from "unplugin";
3
+
4
+ //#region src/unplugin.d.ts
5
+ declare const vizeUnplugin: _$unplugin.UnpluginInstance<VizeUnpluginOptions | undefined, boolean>;
6
+ //#endregion
7
+ export { type VizeUnpluginOptions, vizeUnplugin as default, vizeUnplugin };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { t as vizeUnplugin } from "./unplugin-8tCaeF-H.mjs";
2
+ export { vizeUnplugin as default, vizeUnplugin };
@@ -0,0 +1,7 @@
1
+ import { t as VizeUnpluginOptions } from "./types-o6z7QlYN.mjs";
2
+ import * as _$unplugin from "unplugin";
3
+
4
+ //#region src/rollup.d.ts
5
+ declare const _default: (options?: VizeUnpluginOptions | undefined) => _$unplugin.RollupPlugin<any> | _$unplugin.RollupPlugin<any>[];
6
+ //#endregion
7
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as vizeUnplugin } from "./unplugin-8tCaeF-H.mjs";
2
+ //#region src/rollup.ts
3
+ var rollup_default = vizeUnplugin.rollup;
4
+ //#endregion
5
+ export { rollup_default as default };
@@ -0,0 +1,14 @@
1
+ //#region src/types.d.ts
2
+ interface VizeUnpluginOptions {
3
+ include?: string | RegExp | Array<string | RegExp>;
4
+ exclude?: string | RegExp | Array<string | RegExp>;
5
+ isProduction?: boolean;
6
+ ssr?: boolean;
7
+ sourceMap?: boolean;
8
+ vapor?: boolean;
9
+ customRenderer?: boolean;
10
+ root?: string;
11
+ debug?: boolean;
12
+ }
13
+ //#endregion
14
+ export { VizeUnpluginOptions as t };
@@ -0,0 +1,383 @@
1
+ import fs from "node:fs";
2
+ import { createUnplugin } from "unplugin";
3
+ import { createHash } from "node:crypto";
4
+ import * as native from "@vizejs/native";
5
+ import path from "node:path";
6
+ import { transform } from "oxc-transform";
7
+ //#region src/filter.ts
8
+ function createFilter(include, exclude) {
9
+ const includePatterns = include ? Array.isArray(include) ? include : [include] : [/\.vue$/];
10
+ const excludePatterns = exclude ? Array.isArray(exclude) ? exclude : [exclude] : [/node_modules/];
11
+ return (id) => {
12
+ const matchInclude = includePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
13
+ const matchExclude = excludePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
14
+ return matchInclude && !matchExclude;
15
+ };
16
+ }
17
+ //#endregion
18
+ //#region src/style.ts
19
+ const PREPROCESSOR_LANGS = new Set([
20
+ "scss",
21
+ "sass",
22
+ "less",
23
+ "stylus",
24
+ "styl"
25
+ ]);
26
+ function needsPreprocessor(block) {
27
+ return block.lang !== null && PREPROCESSOR_LANGS.has(block.lang);
28
+ }
29
+ function isCssModule(block) {
30
+ return block.module !== false;
31
+ }
32
+ function hasDelegatedStyles(compiled) {
33
+ return compiled.styles.some((style) => needsPreprocessor(style) || isCssModule(style));
34
+ }
35
+ function generateScopeId(filename, root, isProduction, source) {
36
+ const relative = path.relative(root, filename).replace(/^(\.\.[/\\])+/, "").replace(/\\/g, "/");
37
+ const input = isProduction ? `${relative}\n${source.replace(/\r\n/g, "\n")}` : relative;
38
+ return createHash("sha256").update(input).digest("hex").slice(0, 8);
39
+ }
40
+ function extractStyleBlocks(source) {
41
+ const blocks = [];
42
+ const styleRegex = /<style([^>]*)>([\s\S]*?)<\/style>/gi;
43
+ let match = null;
44
+ let index = 0;
45
+ while ((match = styleRegex.exec(source)) !== null) {
46
+ const attrs = match[1];
47
+ const content = match[2];
48
+ const src = attrs.match(/\bsrc=["']([^"']+)["']/)?.[1] ?? null;
49
+ const lang = attrs.match(/\blang=["']([^"']+)["']/)?.[1] ?? null;
50
+ const scoped = /\bscoped\b/.test(attrs);
51
+ const moduleMatch = attrs.match(/\bmodule(?:=["']([^"']+)["'])?/);
52
+ const moduleValue = moduleMatch ? moduleMatch[1] || true : false;
53
+ blocks.push({
54
+ content,
55
+ src,
56
+ lang,
57
+ scoped,
58
+ module: moduleValue,
59
+ index
60
+ });
61
+ index++;
62
+ }
63
+ return blocks;
64
+ }
65
+ function supportsTemplateOnlyHmr(output) {
66
+ return /(?:^|\n)(?:_sfc_main|__sfc__)\.render\s*=\s*render\b/m.test(output);
67
+ }
68
+ function generateOutput(compiled, options) {
69
+ const { isProduction, isDev, extractCss, filePath } = options;
70
+ let output = compiled.code;
71
+ const exportDefaultRegex = /^export default /m;
72
+ const hasExportDefault = exportDefaultRegex.test(output);
73
+ const hasNamedRenderExport = /^export function render\b/m.test(output);
74
+ const hasSfcMainDefined = /\bconst\s+_sfc_main\s*=/.test(output);
75
+ if (hasExportDefault && !hasSfcMainDefined) {
76
+ output = output.replace(exportDefaultRegex, "const _sfc_main = ");
77
+ if (compiled.hasScoped) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
78
+ output += "\nexport default _sfc_main;";
79
+ } else if (hasExportDefault && hasSfcMainDefined && compiled.hasScoped) output = output.replace(/^export default _sfc_main/m, `_sfc_main.__scopeId = "data-v-${compiled.scopeId}";\nexport default _sfc_main`);
80
+ else if (!hasExportDefault && !hasSfcMainDefined && hasNamedRenderExport) {
81
+ output += "\nconst _sfc_main = {};";
82
+ if (compiled.hasScoped) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
83
+ output += "\n_sfc_main.render = render;";
84
+ output += "\nexport default _sfc_main;";
85
+ }
86
+ if (hasDelegatedStyles(compiled) && filePath) {
87
+ const styleImports = [];
88
+ const cssModuleImports = [];
89
+ for (const block of compiled.styles) {
90
+ const lang = block.lang ?? "css";
91
+ const params = new URLSearchParams();
92
+ params.set("vue", "");
93
+ params.set("type", "style");
94
+ params.set("index", String(block.index));
95
+ params.set("lang", lang);
96
+ if (block.scoped) params.set("scoped", `data-v-${compiled.scopeId}`);
97
+ const importUrl = `${filePath}?${params.toString()}`;
98
+ if (isCssModule(block)) {
99
+ const bindingName = typeof block.module === "string" ? block.module : "$style";
100
+ const moduleParams = new URLSearchParams(params);
101
+ moduleParams.set("module", typeof block.module === "string" ? block.module : "");
102
+ cssModuleImports.push(`import ${bindingName} from ${JSON.stringify(`${filePath}?${moduleParams.toString()}`)};`);
103
+ } else styleImports.push(`import ${JSON.stringify(importUrl)};`);
104
+ }
105
+ const allImports = [...styleImports, ...cssModuleImports].join("\n");
106
+ if (allImports) output = `${allImports}\n${output}`;
107
+ if (cssModuleImports.length > 0) {
108
+ const cssModuleSetup = compiled.styles.filter((block) => isCssModule(block)).map((block) => {
109
+ const bindingName = typeof block.module === "string" ? block.module : "$style";
110
+ return `_sfc_main.__cssModules = _sfc_main.__cssModules || {};\n_sfc_main.__cssModules[${JSON.stringify(bindingName)}] = ${bindingName};`;
111
+ }).join("\n");
112
+ output = output.replace(/^export default _sfc_main;/m, `${cssModuleSetup}\nexport default _sfc_main;`);
113
+ }
114
+ } else if (compiled.css && !(isProduction && extractCss)) output = `
115
+ export const __vize_css__ = ${JSON.stringify(compiled.css)};
116
+ const __vize_css_id__ = ${JSON.stringify(`vize-style-${compiled.scopeId}`)};
117
+ (function() {
118
+ if (typeof document !== "undefined") {
119
+ let style = document.getElementById(__vize_css_id__);
120
+ if (!style) {
121
+ style = document.createElement("style");
122
+ style.id = __vize_css_id__;
123
+ style.textContent = __vize_css__;
124
+ document.head.appendChild(style);
125
+ } else {
126
+ style.textContent = __vize_css__;
127
+ }
128
+ }
129
+ })();
130
+ ${output}`;
131
+ if (!isProduction && isDev && hasExportDefault && supportsTemplateOnlyHmr(output)) output += "";
132
+ return output;
133
+ }
134
+ function wrapScopedPreprocessorStyle(content, scoped, lang) {
135
+ if (!scoped || !lang || lang === "css") return content;
136
+ const lines = content.split("\n");
137
+ const hoisted = [];
138
+ const body = [];
139
+ for (const line of lines) {
140
+ const trimmed = line.trimStart();
141
+ if (trimmed.startsWith("@use ") || trimmed.startsWith("@forward ") || trimmed.startsWith("@import ")) {
142
+ hoisted.push(line);
143
+ continue;
144
+ }
145
+ body.push(line);
146
+ }
147
+ return `${hoisted.length > 0 ? `${hoisted.join("\n")}\n\n` : ""}[${scoped}] {\n${body.join("\n")}\n}`;
148
+ }
149
+ //#endregion
150
+ //#region src/compiler.ts
151
+ const { compileSfc } = native;
152
+ function buildSignature(options) {
153
+ return [
154
+ options.isProduction ? "1" : "0",
155
+ options.ssr ? "1" : "0",
156
+ options.vapor ? "1" : "0",
157
+ options.customRenderer ? "1" : "0",
158
+ options.sourceMap ? "1" : "0",
159
+ options.root
160
+ ].join(":");
161
+ }
162
+ function buildSourceHash(source) {
163
+ return createHash("sha256").update(source).digest("hex");
164
+ }
165
+ function compileVueModule(filePath, source, options, cache) {
166
+ const sourceHash = buildSourceHash(source);
167
+ const signature = buildSignature(options);
168
+ const cached = cache.get(filePath);
169
+ if (cached && cached.sourceHash === sourceHash && cached.signature === signature) return {
170
+ compiled: cached.compiled,
171
+ warnings: []
172
+ };
173
+ const scopeId = generateScopeId(filePath, options.root, options.isProduction, source);
174
+ const hasScoped = /<style[^>]*\bscoped\b/.test(source);
175
+ const result = compileSfc(source, {
176
+ filename: filePath,
177
+ sourceMap: options.sourceMap,
178
+ ssr: options.ssr,
179
+ vapor: options.vapor,
180
+ customRenderer: options.customRenderer,
181
+ scopeId: hasScoped ? `data-v-${scopeId}` : void 0
182
+ });
183
+ if (result.errors.length > 0) throw new Error(result.errors.join("\n"));
184
+ const compiled = {
185
+ code: result.code,
186
+ css: result.css,
187
+ scopeId,
188
+ hasScoped,
189
+ templateHash: result.templateHash,
190
+ styleHash: result.styleHash,
191
+ scriptHash: result.scriptHash,
192
+ styles: extractStyleBlocks(source)
193
+ };
194
+ cache.set(filePath, {
195
+ compiled,
196
+ sourceHash,
197
+ signature
198
+ });
199
+ return {
200
+ compiled,
201
+ warnings: result.warnings
202
+ };
203
+ }
204
+ //#endregion
205
+ //#region src/request.ts
206
+ const STYLE_MARKER = ".__vize_style_";
207
+ function isVueFile(id) {
208
+ return id.endsWith(".vue");
209
+ }
210
+ function isVueStyleRequest(id) {
211
+ const { query } = parseVueRequest(id);
212
+ return query.vue && query.type === "style";
213
+ }
214
+ function isVirtualStyleId(id) {
215
+ return id.includes(STYLE_MARKER);
216
+ }
217
+ function parseVueRequest(id) {
218
+ const [path, rawQuery = ""] = id.split("?", 2);
219
+ const params = new URLSearchParams(rawQuery);
220
+ const filename = params.get("vize-file") ?? path;
221
+ const moduleValue = params.has("module") ? params.get("module") || true : false;
222
+ const indexValue = params.get("index");
223
+ return {
224
+ filename,
225
+ path,
226
+ query: {
227
+ vue: params.has("vue"),
228
+ type: params.get("type"),
229
+ index: indexValue === null ? null : Number.parseInt(indexValue, 10),
230
+ lang: params.get("lang"),
231
+ module: moduleValue,
232
+ scoped: params.get("scoped"),
233
+ vizeFile: params.get("vize-file")
234
+ }
235
+ };
236
+ }
237
+ function createVirtualStyleId(id) {
238
+ const { filename, query } = parseVueRequest(id);
239
+ const index = query.index ?? 0;
240
+ const lang = query.lang ?? "css";
241
+ const suffix = query.module !== false ? `.module.${lang}` : `.${lang}`;
242
+ const params = new URLSearchParams();
243
+ params.set("vue", "");
244
+ params.set("type", "style");
245
+ params.set("index", String(index));
246
+ params.set("lang", lang);
247
+ params.set("vize-file", filename);
248
+ if (query.scoped) params.set("scoped", query.scoped);
249
+ if (query.module !== false) params.set("module", typeof query.module === "string" ? query.module : "");
250
+ return `${filename}${STYLE_MARKER}${index}${suffix}?${params.toString()}`;
251
+ }
252
+ //#endregion
253
+ //#region src/strip-types.ts
254
+ function formatErrorMessage(error) {
255
+ const parts = [error.message];
256
+ if (error.helpMessage) parts.push(error.helpMessage);
257
+ if (error.codeframe) parts.push(error.codeframe);
258
+ return parts.join("\n");
259
+ }
260
+ async function stripTypeScript(filePath, code, sourceMap) {
261
+ const result = transform(filePath, code, {
262
+ lang: "ts",
263
+ sourcemap: sourceMap,
264
+ sourceType: "module"
265
+ });
266
+ if (result.errors.length > 0) throw new Error(result.errors.map(formatErrorMessage).join("\n\n"));
267
+ return {
268
+ code: result.code,
269
+ map: result.map ?? null
270
+ };
271
+ }
272
+ //#endregion
273
+ //#region src/unplugin.ts
274
+ function normalizeOptions(rawOptions = {}) {
275
+ const isProduction = rawOptions.isProduction ?? process.env.NODE_ENV === "production";
276
+ return {
277
+ include: rawOptions.include,
278
+ exclude: rawOptions.exclude,
279
+ isProduction,
280
+ ssr: rawOptions.ssr ?? false,
281
+ sourceMap: rawOptions.sourceMap ?? !isProduction,
282
+ vapor: rawOptions.vapor ?? false,
283
+ customRenderer: rawOptions.customRenderer ?? false,
284
+ root: rawOptions.root ?? process.cwd(),
285
+ debug: rawOptions.debug ?? false
286
+ };
287
+ }
288
+ function createVueDefineMap(isProduction) {
289
+ return {
290
+ __VUE_OPTIONS_API__: JSON.stringify(true),
291
+ __VUE_PROD_DEVTOOLS__: JSON.stringify(!isProduction),
292
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: JSON.stringify(!isProduction)
293
+ };
294
+ }
295
+ function injectWebpackVueDefines(compiler, isProduction) {
296
+ const { DefinePlugin } = compiler.webpack;
297
+ const existingDefines = /* @__PURE__ */ new Set();
298
+ for (const plugin of compiler.options.plugins ?? []) {
299
+ const definitions = plugin.definitions;
300
+ if (!definitions) continue;
301
+ for (const key of Object.keys(definitions)) existingDefines.add(key);
302
+ }
303
+ const definitions = createVueDefineMap(isProduction);
304
+ const missingDefinitions = {};
305
+ for (const [key, value] of Object.entries(definitions)) if (!existingDefines.has(key)) missingDefinitions[key] = value;
306
+ if (Object.keys(missingDefinitions).length > 0) new DefinePlugin(missingDefinitions).apply(compiler);
307
+ }
308
+ async function loadStyleBlock(id, options, cache) {
309
+ const request = parseVueRequest(id);
310
+ const index = request.query.index ?? -1;
311
+ if (index < 0) return "";
312
+ let compiled = cache.get(request.filename)?.compiled;
313
+ if (!compiled && fs.existsSync(request.filename)) {
314
+ const source = fs.readFileSync(request.filename, "utf8");
315
+ compiled = compileVueModule(request.filename, source, options, cache).compiled;
316
+ }
317
+ const block = compiled?.styles[index];
318
+ if (!block) return "";
319
+ return wrapScopedPreprocessorStyle(block.content, request.query.scoped, block.lang);
320
+ }
321
+ const vizeUnplugin = createUnplugin((rawOptions = {}) => {
322
+ const options = normalizeOptions(rawOptions);
323
+ const filter = createFilter(options.include, options.exclude);
324
+ const cache = /* @__PURE__ */ new Map();
325
+ return {
326
+ name: "unplugin-vize",
327
+ resolveId(id) {
328
+ if (isVueStyleRequest(id)) return createVirtualStyleId(id);
329
+ return null;
330
+ },
331
+ loadInclude(id) {
332
+ return isVirtualStyleId(id);
333
+ },
334
+ async load(id) {
335
+ if (!isVirtualStyleId(id)) return null;
336
+ return {
337
+ code: await loadStyleBlock(id, options, cache),
338
+ map: null
339
+ };
340
+ },
341
+ transformInclude(id) {
342
+ const request = parseVueRequest(id);
343
+ return !request.query.vue && isVueFile(request.filename) && filter(request.filename);
344
+ },
345
+ async transform(code, id) {
346
+ if (!isVueFile(id) || !filter(id)) return null;
347
+ const { compiled, warnings } = compileVueModule(id, code, options, cache);
348
+ for (const warning of warnings) this.warn(`[vize] ${warning}`);
349
+ const transformed = await stripTypeScript(id, generateOutput(compiled, {
350
+ isProduction: options.isProduction,
351
+ isDev: false,
352
+ filePath: id
353
+ }), options.sourceMap);
354
+ return {
355
+ code: transformed.code,
356
+ map: transformed.map
357
+ };
358
+ },
359
+ watchChange(id) {
360
+ if (isVueFile(id)) cache.delete(id);
361
+ },
362
+ webpack(compiler) {
363
+ injectWebpackVueDefines(compiler, options.isProduction);
364
+ },
365
+ esbuild: {
366
+ onResolveFilter: /\.vue(?:$|\?)/,
367
+ onLoadFilter: /\.vue(?:$|\?)/,
368
+ loader(_code, id) {
369
+ const request = parseVueRequest(id);
370
+ if (request.query.type === "style") return request.query.module !== false ? "local-css" : "css";
371
+ return "js";
372
+ },
373
+ config(buildOptions) {
374
+ buildOptions.define = {
375
+ ...createVueDefineMap(options.isProduction),
376
+ ...buildOptions.define
377
+ };
378
+ }
379
+ }
380
+ };
381
+ });
382
+ //#endregion
383
+ export { vizeUnplugin as t };
@@ -0,0 +1,6 @@
1
+ import { t as VizeUnpluginOptions } from "./types-o6z7QlYN.mjs";
2
+
3
+ //#region src/webpack.d.ts
4
+ declare const _default: (options?: VizeUnpluginOptions | undefined) => undefined;
5
+ //#endregion
6
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as vizeUnplugin } from "./unplugin-8tCaeF-H.mjs";
2
+ //#region src/webpack.ts
3
+ var webpack_default = vizeUnplugin.webpack;
4
+ //#endregion
5
+ export { webpack_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/unplugin",
3
- "version": "0.58.0",
3
+ "version": "0.60.0",
4
4
  "description": "Experimental unplugin-based Vue SFC integration for rollup, webpack, and esbuild powered by Vize",
5
5
  "keywords": [
6
6
  "compiler",
@@ -51,7 +51,7 @@
51
51
  "access": "public"
52
52
  },
53
53
  "dependencies": {
54
- "@vizejs/native": "0.58.0",
54
+ "@vizejs/native": "0.60.0",
55
55
  "oxc-transform": "0.56.5",
56
56
  "unplugin": "3.0.0"
57
57
  },