@vizejs/vite-plugin-musea 0.327.0 → 0.332.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/dist/index.mjs CHANGED
@@ -1102,6 +1102,108 @@ function resolveComponentSourcePath(art, artPath, sourceRoots) {
1102
1102
  return componentPath ? resolveInsideAny(sourceRoots, componentPath, "component path") : null;
1103
1103
  }
1104
1104
  //#endregion
1105
+ //#region src/art-module-vue2.ts
1106
+ /**
1107
+ * Legacy Vue 2 variant emission.
1108
+ *
1109
+ * Vue 2 has no `openBlock`/`createElementBlock` runtime, so the compiled Vue 3
1110
+ * render functions the SFC pipeline produces cannot load there. Vue 2 galleries
1111
+ * keep the runtime-compiled `template:` string they always had — the TypeScript
1112
+ * fix in #3857 applies to Vue 3, which is what `.art.vue` with
1113
+ * `<script setup lang="ts">` targets.
1114
+ */
1115
+ function escapeTemplateLiteral(str) {
1116
+ return str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
1117
+ }
1118
+ function emitLegacyVariant(context) {
1119
+ const { variantComponentName, variantName, template, componentTagName, componentBindingName, scriptSetup, hasSetup, isolatedSetup, setupReturn, importDeclaresName } = context;
1120
+ const escapedTemplate = escapeTemplateLiteral(template);
1121
+ const fullTemplate = `<div data-variant="${escapeTemplateLiteral(escapeHtml(variantName))}">${escapedTemplate}</div>`;
1122
+ const componentNames = /* @__PURE__ */ new Map();
1123
+ if (componentTagName) componentNames.set(componentTagName, componentBindingName);
1124
+ if (scriptSetup) {
1125
+ for (const name of scriptSetup.returnNames) if (/^[A-Z]/.test(name) && scriptSetup.imports.some((imp) => importDeclaresName(imp, name))) componentNames.set(name, name);
1126
+ }
1127
+ const components = componentNames.size > 0 ? ` components: { ${[...componentNames].map(([name, value]) => `${JSON.stringify(name)}: ${value}`).join(", ")} },\n` : "";
1128
+ if (scriptSetup && hasSetup && isolatedSetup) return `
1129
+ export const ${variantComponentName} = __museaDefineComponent({
1130
+ name: '${variantComponentName}',
1131
+ ${components} setup() {
1132
+ ${scriptSetup.setupBody.join("\n")}
1133
+ return ${setupReturn};
1134
+ },
1135
+ template: \`${fullTemplate}\`,
1136
+ });
1137
+ `;
1138
+ if (scriptSetup && hasSetup) return `
1139
+ export const ${variantComponentName} = __museaDefineComponent({
1140
+ name: '${variantComponentName}',
1141
+ ${components} setup() {
1142
+ return __museaSharedSetup;
1143
+ },
1144
+ template: \`${fullTemplate}\`,
1145
+ });
1146
+ `;
1147
+ return `
1148
+ export const ${variantComponentName} = {
1149
+ name: '${variantComponentName}',
1150
+ ${components} template: \`${fullTemplate}\`,
1151
+ };
1152
+ `;
1153
+ }
1154
+ //#endregion
1155
+ //#region src/art-component.ts
1156
+ /**
1157
+ * Resolve which component an art file demonstrates, and under what tag.
1158
+ *
1159
+ * Shared by the art module and by the per-variant SFC compiler (#3857) so both
1160
+ * agree on the import path, the tag `<Self>` expands to, and the binding name.
1161
+ * The parsed `<script setup>` is passed in rather than parsed here, so this
1162
+ * module does not have to import back from `art-module.ts`.
1163
+ */
1164
+ function componentNameFromSource$1(source) {
1165
+ const withoutQuery = source.split(/[?#]/, 1)[0] || source;
1166
+ const filename = path.basename(withoutQuery);
1167
+ const extension = path.extname(filename);
1168
+ const name = toPascalCase(extension ? filename.slice(0, -extension.length) : filename);
1169
+ return name === "Variant" ? "MuseaComponent" : name;
1170
+ }
1171
+ function resolveArtComponent(art, filePath, scriptSetup, options = {}) {
1172
+ let componentImportPath;
1173
+ let componentTagName;
1174
+ let componentBindingName = "__MuseaComponent";
1175
+ const defineArtComponentName = scriptSetup?.defineArtComponentName;
1176
+ const defineArtComponentSource = scriptSetup?.defineArtComponentSource;
1177
+ if (art.isInline && art.componentPath) {
1178
+ componentImportPath = options.root ? resolveComponentSourcePath(art, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : art.componentPath;
1179
+ componentTagName = "MuseaComponent";
1180
+ } else if (defineArtComponentSource || art.metadata.component) {
1181
+ const componentSource = defineArtComponentSource ?? art.metadata.component;
1182
+ if (componentSource) {
1183
+ const sourceArt = componentSource === art.metadata.component ? art : {
1184
+ ...art,
1185
+ metadata: {
1186
+ ...art.metadata,
1187
+ component: componentSource
1188
+ }
1189
+ };
1190
+ componentImportPath = options.root ? resolveComponentSourcePath(sourceArt, filePath, allowedSourceRoots(options.root, options.scanRoots ?? [])) ?? void 0 : path.isAbsolute(componentSource) ? componentSource : path.resolve(path.dirname(filePath), componentSource);
1191
+ }
1192
+ componentTagName = defineArtComponentName ?? (art.metadata.component ? componentNameFromSource$1(art.metadata.component) : "MuseaComponent");
1193
+ componentBindingName = componentTagName;
1194
+ }
1195
+ return {
1196
+ componentImportPath,
1197
+ componentTagName,
1198
+ componentBindingName
1199
+ };
1200
+ }
1201
+ /** Expand `<Self>` in a variant template to the resolved component tag. */
1202
+ function expandSelfTag(template, componentTagName) {
1203
+ if (!componentTagName) return template;
1204
+ return template.replace(/<Self(?=[\s/>])/g, `<${componentTagName}`).replace(/<\/Self\s*>/g, `</${componentTagName}>`);
1205
+ }
1206
+ //#endregion
1105
1207
  //#region src/art-module.ts
1106
1208
  /**
1107
1209
  * Art module generation for Musea.
@@ -1128,9 +1230,6 @@ function resolveRelativeSpecifier(specifier, artDir) {
1128
1230
  function rewriteRelativeImportStatement(statement, artDir) {
1129
1231
  return statement.replace(/\bfrom\s+(['"])([^'"]+)\1/g, (_match, quote, specifier) => `from ${quote}${resolveRelativeSpecifier(specifier, artDir)}${quote}`).replace(/^(\s*import\s+)(['"])([^'"]+)\2(\s*;?\s*)$/s, (_match, prefix, quote, specifier, suffix) => `${prefix}${quote}${resolveRelativeSpecifier(specifier, artDir)}${quote}${suffix}`);
1130
1232
  }
1131
- function escapeTemplateLiteral(str) {
1132
- return str.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
1133
- }
1134
1233
  function countCharBalance(source, openChar, closeChar) {
1135
1234
  let balance = 0;
1136
1235
  for (const char of source) if (char === openChar) balance++;
@@ -1360,10 +1459,12 @@ function generateArtModule(art, filePath, options = {}) {
1360
1459
  componentTagName = defineArtComponentName ?? (art.metadata.component ? componentNameFromSource(art.metadata.component) : "MuseaComponent");
1361
1460
  componentBindingName = componentTagName;
1362
1461
  }
1462
+ const hasSetupBody = scriptSetup?.setupBody.some((line) => line.trim().length > 0) ?? false;
1463
+ const hasSetup = !!scriptSetup && (hasSetupBody || scriptSetup.returnNames.length > 0);
1363
1464
  let code = `
1364
1465
  // Auto-generated module for: ${path.basename(filePath)}
1365
- import { defineComponent as __museaDefineComponent } from 'vue';
1366
1466
  `;
1467
+ if (options.vueVersion === 2 && hasSetup) code += `import { defineComponent as __museaDefineComponent } from 'vue';\n`;
1367
1468
  if (scriptSetup) {
1368
1469
  const artDir = path.dirname(filePath);
1369
1470
  for (const imp of scriptSetup.imports) {
@@ -1380,8 +1481,6 @@ export const metadata = ${JSON.stringify(art.metadata)};
1380
1481
  export const variants = ${JSON.stringify(art.variants)};
1381
1482
  export const __styles__ = ${JSON.stringify(art.styleBlocks ?? [])};
1382
1483
  `;
1383
- const hasSetupBody = scriptSetup?.setupBody.some((line) => line.trim().length > 0) ?? false;
1384
- const hasSetup = !!scriptSetup && (hasSetupBody || scriptSetup.returnNames.length > 0);
1385
1484
  const setupReturn = `{ ${scriptSetup?.returnNames.join(", ") ?? ""} }`;
1386
1485
  const isolatedSetup = art.scriptSetupIsolated !== false;
1387
1486
  if (scriptSetup && hasSetup && !isolatedSetup) code += `
@@ -1392,46 +1491,26 @@ ${scriptSetup.setupBody.join("\n")}
1392
1491
  `;
1393
1492
  for (const variant of art.variants) {
1394
1493
  const variantComponentName = toPascalCase(variant.name);
1395
- let template = variant.template;
1396
- if (componentTagName) template = template.replace(/<Self/g, `<${componentTagName}`).replace(/<\/Self>/g, `</${componentTagName}>`);
1397
- const escapedTemplate = escapeTemplateLiteral(template);
1398
- const fullTemplate = `<div data-variant="${escapeTemplateLiteral(escapeHtml(variant.name))}">${escapedTemplate}</div>`;
1399
- const componentNames = /* @__PURE__ */ new Map();
1400
- if (componentTagName) componentNames.set(componentTagName, componentBindingName);
1401
- if (scriptSetup) {
1402
- for (const name of scriptSetup.returnNames) if (/^[A-Z]/.test(name) && scriptSetup.imports.some((imp) => importDeclaresName(imp, name))) componentNames.set(name, name);
1403
- }
1404
- const components = componentNames.size > 0 ? ` components: { ${[...componentNames].map(([name, value]) => `${JSON.stringify(name)}: ${value}`).join(", ")} },\n` : "";
1405
- if (scriptSetup && hasSetup && isolatedSetup) code += `
1406
- export const ${variantComponentName} = __museaDefineComponent({
1407
- name: '${variantComponentName}',
1408
- ${components} setup() {
1409
- ${scriptSetup.setupBody.join("\n")}
1410
- return ${setupReturn};
1411
- },
1412
- template: \`${fullTemplate}\`,
1413
- });
1414
- `;
1415
- else if (scriptSetup && hasSetup) code += `
1416
- export const ${variantComponentName} = __museaDefineComponent({
1417
- name: '${variantComponentName}',
1418
- ${components} setup() {
1419
- return __museaSharedSetup;
1420
- },
1421
- template: \`${fullTemplate}\`,
1422
- });
1423
- `;
1424
- else if (componentTagName) code += `
1425
- export const ${variantComponentName} = {
1426
- name: '${variantComponentName}',
1427
- ${components} template: \`${fullTemplate}\`,
1428
- };
1429
- `;
1430
- else code += `
1431
- export const ${variantComponentName} = {
1432
- name: '${variantComponentName}',
1433
- template: \`${fullTemplate}\`,
1434
- };
1494
+ const template = expandSelfTag(variant.template, componentTagName);
1495
+ if (options.vueVersion === 2) {
1496
+ code += emitLegacyVariant({
1497
+ variantComponentName,
1498
+ variantName: variant.name,
1499
+ template,
1500
+ componentTagName,
1501
+ componentBindingName,
1502
+ scriptSetup,
1503
+ hasSetup,
1504
+ isolatedSetup,
1505
+ setupReturn,
1506
+ importDeclaresName
1507
+ });
1508
+ continue;
1509
+ }
1510
+ const variantModuleId = `virtual:musea-variant:${filePath}:${encodeURIComponent(variant.name)}`;
1511
+ code += `
1512
+ import ${variantComponentName} from ${JSON.stringify(variantModuleId)};
1513
+ export { ${variantComponentName} };
1435
1514
  `;
1436
1515
  }
1437
1516
  const defaultVariant = art.variants.find((v) => v.isDefault) || art.variants[0];
@@ -3173,6 +3252,123 @@ function generateManifestModule(artFiles) {
3173
3252
  return `export const arts = ${JSON.stringify(arts, null, 2)};`;
3174
3253
  }
3175
3254
  //#endregion
3255
+ //#region src/art-variant-sfc.ts
3256
+ /**
3257
+ * Compile an `<art>` variant through the SFC pipeline.
3258
+ *
3259
+ * Variants used to be emitted as `template:` strings for Vue's runtime
3260
+ * compiler, which never sees the SFC pipeline. Any template expression relying
3261
+ * on SFC-time compilation therefore failed at render time — most importantly
3262
+ * TypeScript, even though `.art.vue` files are authored with
3263
+ * `<script setup lang="ts">` (#3857).
3264
+ *
3265
+ * Compiling the raw template with the template compiler is not enough: it
3266
+ * leaves TypeScript in place *and* its identifier prefixer gives up on TS
3267
+ * syntax, so `items[0]!.isValid` stays unprefixed and throws at runtime. Only
3268
+ * the SFC pipeline handles both, which is what the issue asks for — the variant
3269
+ * is compiled the same way the enclosing SFC is:
3270
+ *
3271
+ * :disabled="items[0]!.isValid" -> disabled: items.value[0].isValid
3272
+ * @u="(f: File | null) => …" -> onU: (f) => file.value = f
3273
+ */
3274
+ /**
3275
+ * Rebase the art file's `<script setup>` for a virtual module.
3276
+ *
3277
+ * A variant compiles into a virtual module, and a relative specifier cannot be
3278
+ * resolved from one — the art module rebases its own imports for exactly this
3279
+ * reason, and the variant needs the same treatment or every relative import in
3280
+ * an art file fails to resolve.
3281
+ */
3282
+ function rebaseScriptSetup(scriptSetup, artDir) {
3283
+ if (!scriptSetup.trim()) return "";
3284
+ const parsed = parseScriptSetupForArt(scriptSetup);
3285
+ return [...parsed.imports.map((statement) => rewriteRelativeImportStatement(statement, artDir)), ...parsed.setupBody].join("\n").trim();
3286
+ }
3287
+ /**
3288
+ * Build the synthetic SFC source for one variant.
3289
+ *
3290
+ * The art file's own `<script setup>` becomes the variant's setup block, so
3291
+ * bindings resolve exactly as they do in the authored file, and `lang="ts"` is
3292
+ * carried over so the pipeline strips TypeScript from template expressions.
3293
+ */
3294
+ function buildVariantSfcSource(art, variantTemplate, variantName, options = {}) {
3295
+ if (options.sharedBindings && options.sharedBindings.names.length > 0) {
3296
+ const { moduleId, names } = options.sharedBindings;
3297
+ const escapedShared = variantName.replace(/"/g, "&quot;");
3298
+ return `<script setup lang="ts">\n` + (options.componentImportPath && options.componentBindingName && !names.includes(options.componentBindingName) ? `import ${options.componentBindingName} from ${JSON.stringify(options.componentImportPath)}\n` : "") + `import { ${names.join(", ")} } from ${JSON.stringify(moduleId)}\n<\/script>\n<template><div data-variant="${escapedShared}">${variantTemplate}</div></template>\n`;
3299
+ }
3300
+ const scriptSetup = rebaseScriptSetup(options.scriptSetup ?? art.scriptSetupContent ?? "", path.dirname(options.artFilePath ?? art.path));
3301
+ return `${`<script setup lang="ts">\n${`${options.componentImportPath && options.componentBindingName ? `import ${options.componentBindingName} from ${JSON.stringify(options.componentImportPath)}\n` : ""}${scriptSetup.trim()}`.trim()}\n<\/script>\n`}<template><div data-variant="${variantName.replace(/"/g, "&quot;")}">${variantTemplate}</div></template>\n`;
3302
+ }
3303
+ /**
3304
+ * Compile a variant to a self-contained ES module exporting the component.
3305
+ *
3306
+ * Each variant compiles to its own module because `compileSfc` emits a complete
3307
+ * module with its own `export default` and imports; concatenating several into
3308
+ * one art module would redeclare bindings and collide on the default export.
3309
+ */
3310
+ function compileVariantSfc(art, variantTemplate, variantName, filename, options = {}) {
3311
+ const component = resolveArtComponent(art, filename, options.parsedScriptSetup ?? null, {
3312
+ root: options.root,
3313
+ scanRoots: options.scanRoots
3314
+ });
3315
+ const source = buildVariantSfcSource(art, expandSelfTag(variantTemplate, component.componentTagName), variantName, {
3316
+ scriptSetup: options.scriptSetup,
3317
+ componentImportPath: component.componentImportPath,
3318
+ componentBindingName: component.componentBindingName,
3319
+ artFilePath: filename,
3320
+ sharedBindings: options.sharedBindings
3321
+ });
3322
+ const result = loadNative().compileSfc(source, { filename });
3323
+ return {
3324
+ code: result.code ?? "",
3325
+ errors: (result.errors ?? []).map((error) => typeof error === "string" ? error : error.message ?? JSON.stringify(error))
3326
+ };
3327
+ }
3328
+ //#endregion
3329
+ //#region src/art-shared-setup.ts
3330
+ /**
3331
+ * One shared `<script setup>` instance for an art file's variants.
3332
+ *
3333
+ * `scriptSetupIsolated: false` opts an art file out of per-variant isolation:
3334
+ * every variant sees the same setup instance, so state written in one variant is
3335
+ * visible in the next. Compiling each variant as its own SFC (#3857) would give
3336
+ * each one its own setup and silently drop that, so the shared case hoists the
3337
+ * setup into this module and the variants import its bindings instead of
3338
+ * declaring them.
3339
+ *
3340
+ * A dedicated module rather than the art module itself, because the art module
3341
+ * imports the variants — routing the shared state through it would make that a
3342
+ * cycle.
3343
+ */
3344
+ /**
3345
+ * The binding names a variant SFC should import from the shared module.
3346
+ *
3347
+ * `<script setup>` resolves template identifiers from its own bindings, and an
3348
+ * import is a binding, so importing each name by hand is what makes the shared
3349
+ * state reachable from the variant's template.
3350
+ */
3351
+ function sharedBindingNames(parsed) {
3352
+ return [...new Set(parsed.returnNames)].filter((name) => /^[A-Za-z_$][\w$]*$/.test(name));
3353
+ }
3354
+ function generateSharedSetupModule(art, filePath) {
3355
+ const parsed = parseSharedScriptSetup(art);
3356
+ if (!parsed) return "export {};\n";
3357
+ const artDir = path.dirname(filePath);
3358
+ const imports = parsed.imports.map((statement) => rewriteRelativeImportStatement(statement, artDir)).join("\n");
3359
+ const names = sharedBindingNames(parsed);
3360
+ return [
3361
+ imports,
3362
+ parsed.setupBody.join("\n"),
3363
+ names.length > 0 ? `export { ${names.join(", ")} };` : "export {};",
3364
+ ""
3365
+ ].join("\n");
3366
+ }
3367
+ function parseSharedScriptSetup(art) {
3368
+ if (!art.scriptSetupContent) return null;
3369
+ return parseScriptSetupForArt(art.scriptSetupContent);
3370
+ }
3371
+ //#endregion
3176
3372
  //#region src/plugin/virtual.ts
3177
3373
  /**
3178
3374
  * Virtual module handling for the Musea Vite plugin.
@@ -3183,12 +3379,28 @@ function generateManifestModule(artFiles) {
3183
3379
  const VIRTUAL_MUSEA_PREFIX = "\0musea:";
3184
3380
  const VIRTUAL_GALLERY = "\0musea-gallery";
3185
3381
  const VIRTUAL_MANIFEST = "\0musea-manifest";
3382
+ /**
3383
+ * Recover a variant name from a virtual module id.
3384
+ *
3385
+ * `generateArtModule` percent-encodes it, so a hand-written import with an
3386
+ * invalid escape still falls back to the raw text instead of throwing a
3387
+ * `URIError` out of `load`.
3388
+ */
3389
+ function decodeVariantName(encoded) {
3390
+ try {
3391
+ return decodeURIComponent(encoded);
3392
+ } catch {
3393
+ return encoded;
3394
+ }
3395
+ }
3186
3396
  function createResolveId(state) {
3187
3397
  return function resolveId(id) {
3188
3398
  const root = state.getConfigRoot();
3189
3399
  if (id === "\0musea-gallery") return VIRTUAL_GALLERY;
3190
3400
  if (id === "\0musea-manifest") return VIRTUAL_MANIFEST;
3191
3401
  if (id.startsWith("virtual:musea-preview:")) return "\0musea-preview:" + id.slice(22);
3402
+ if (id.startsWith("virtual:musea-variant:")) return "\0musea-variant:" + id.slice(22) + "?musea-virtual";
3403
+ if (id.startsWith("virtual:musea-shared:")) return "\0musea-shared:" + id.slice(21) + "?musea-virtual";
3192
3404
  if (id.startsWith("virtual:musea-art:")) {
3193
3405
  const artPath = id.slice(18);
3194
3406
  if (state.artFiles.has(artPath)) return "\0musea-art:" + artPath + "?musea-virtual";
@@ -3218,12 +3430,45 @@ function createLoad(state) {
3218
3430
  if (art) return generatePreviewModule(art, toPascalCase(variantName), variantName, state.resolvedPreviewCss, state.resolvedPreviewSetup, state.getVueVersion());
3219
3431
  }
3220
3432
  }
3433
+ if (id.startsWith("\0musea-shared:")) {
3434
+ const artPath = id.slice(14).replace(/\?musea-virtual$/, "");
3435
+ const art = state.artFiles.get(artPath);
3436
+ if (art) return generateSharedSetupModule(art, artPath);
3437
+ }
3438
+ if (id.startsWith("\0musea-variant:")) {
3439
+ const rest = id.slice(15).replace(/\?musea-virtual$/, "");
3440
+ const lastColonIndex = rest.lastIndexOf(":");
3441
+ if (lastColonIndex !== -1) {
3442
+ const artPath = rest.slice(0, lastColonIndex);
3443
+ const variantName = decodeVariantName(rest.slice(lastColonIndex + 1));
3444
+ const art = state.artFiles.get(artPath);
3445
+ const variant = art?.variants.find((candidate) => candidate.name === variantName);
3446
+ if (art && variant) {
3447
+ const parsedScriptSetup = art.scriptSetupContent ? parseScriptSetupForArt(art.scriptSetupContent) : null;
3448
+ const shared = art.scriptSetupIsolated === false && parsedScriptSetup ? {
3449
+ moduleId: `virtual:musea-shared:${artPath}`,
3450
+ names: sharedBindingNames(parsedScriptSetup)
3451
+ } : void 0;
3452
+ const compiled = compileVariantSfc(art, variant.template, variant.name, artPath, {
3453
+ scriptSetup: art.scriptSetupContent,
3454
+ parsedScriptSetup,
3455
+ root: state.getConfigRoot(),
3456
+ scanRoots: state.getScanRoots(),
3457
+ sharedBindings: shared
3458
+ });
3459
+ if (compiled.errors.length > 0) throw new Error(`Failed to compile <art> variant "${variantName}" in ${artPath}:\n${compiled.errors.join("\n")}`);
3460
+ if (!compiled.code) throw new Error(`The compiler produced no code for <art> variant "${variantName}" in ${artPath}.`);
3461
+ return compiled.code;
3462
+ }
3463
+ }
3464
+ }
3221
3465
  if (id.startsWith("\0musea-art:")) {
3222
3466
  const artPath = id.slice(11).replace(/\?musea-virtual$/, "");
3223
3467
  const art = state.artFiles.get(artPath);
3224
3468
  if (art) return generateArtModule(art, artPath, {
3225
3469
  root: state.getConfigRoot(),
3226
- scanRoots: state.getScanRoots()
3470
+ scanRoots: state.getScanRoots(),
3471
+ vueVersion: state.getVueVersion()
3227
3472
  });
3228
3473
  }
3229
3474
  if (id.startsWith("\0musea:")) {
@@ -3231,7 +3476,8 @@ function createLoad(state) {
3231
3476
  const art = state.artFiles.get(realPath);
3232
3477
  if (art) return generateArtModule(art, realPath, {
3233
3478
  root: state.getConfigRoot(),
3234
- scanRoots: state.getScanRoots()
3479
+ scanRoots: state.getScanRoots(),
3480
+ vueVersion: state.getVueVersion()
3235
3481
  });
3236
3482
  }
3237
3483
  return null;