@lewebsimple/nuxt-graphql 0.1.7 → 0.1.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 +21 -1
- package/dist/module.d.mts +0 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +70 -63
- package/dist/runtime/composables/useGraphQLMutation.d.ts +6 -7
- package/dist/runtime/composables/useGraphQLMutation.js +4 -8
- package/dist/runtime/composables/useGraphQLQuery.d.ts +1 -2
- package/dist/runtime/composables/useGraphQLQuery.js +1 -1
- package/dist/runtime/utils/helpers.d.ts +1 -0
- package/dist/runtime/utils/helpers.js +0 -0
- package/dist/templates/yoga-handler.mjs +15 -5
- package/package.json +19 -15
package/README.md
CHANGED
|
@@ -23,6 +23,25 @@ Install the module to your Nuxt application with one command:
|
|
|
23
23
|
npx nuxi module add @lewebsimple/nuxt-graphql
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
Optionnally adjust options in your Nuxt config. The defaults shown below:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// nuxt.config.ts
|
|
30
|
+
export default defineNuxtConfig({
|
|
31
|
+
modules: ["@lewebsimple/nuxt-graphql"],
|
|
32
|
+
graphql: {
|
|
33
|
+
// GraphQL HTTP endpoint served by Yoga
|
|
34
|
+
endpoint: "/api/graphql",
|
|
35
|
+
// Codegen controls document scanning and outputs
|
|
36
|
+
codegen: {
|
|
37
|
+
enabled: true,
|
|
38
|
+
pattern: "**/*.gql", // scan .gql files across layers
|
|
39
|
+
schemaOutput: "server/graphql/schema.graphql", // saved SDL
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
26
45
|
Define your GraphQL schema in `server/graphql/schema.ts`:
|
|
27
46
|
|
|
28
47
|
```ts
|
|
@@ -43,7 +62,7 @@ export const schema = createSchema<GraphQLContext>({
|
|
|
43
62
|
});
|
|
44
63
|
```
|
|
45
64
|
|
|
46
|
-
|
|
65
|
+
Optionnally define your GraphQL context in `server/graphql/context.ts`:
|
|
47
66
|
|
|
48
67
|
```ts
|
|
49
68
|
import type { H3Event } from "h3";
|
|
@@ -59,6 +78,7 @@ export type GraphQLContext = Awaited<ReturnType<typeof createContext>>;
|
|
|
59
78
|
|
|
60
79
|
That's it! You can now use Nuxt GraphQL in your Nuxt app ✨
|
|
61
80
|
|
|
81
|
+
Yoga GraphiQL is available at `http://localhost:3000/api/graphql` by default.
|
|
62
82
|
|
|
63
83
|
## Contribution
|
|
64
84
|
|
package/dist/module.d.mts
CHANGED
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -44,6 +44,16 @@ function writeFileIfChanged(path, content) {
|
|
|
44
44
|
return true;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
async function loadGraphQLSchema(schemaPath) {
|
|
48
|
+
const { createJiti } = await import('jiti');
|
|
49
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
50
|
+
const module = await jiti.import(schemaPath);
|
|
51
|
+
if (!module.schema) {
|
|
52
|
+
throw new Error(`${schemaPath} must export a 'schema' variable`);
|
|
53
|
+
}
|
|
54
|
+
const { printSchema, lexicographicSortSchema } = await import('graphql');
|
|
55
|
+
return printSchema(lexicographicSortSchema(module.schema));
|
|
56
|
+
}
|
|
47
57
|
function analyzeGraphQLDocuments(docs) {
|
|
48
58
|
const byFile = /* @__PURE__ */ new Map();
|
|
49
59
|
const operationsByType = {
|
|
@@ -92,9 +102,9 @@ function analyzeGraphQLDocuments(docs) {
|
|
|
92
102
|
return { byFile, operationsByType };
|
|
93
103
|
}
|
|
94
104
|
function generateRegistryByTypeSource(analysis) {
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
const
|
|
105
|
+
const queries = analysis.query.map((o) => o.name);
|
|
106
|
+
const mutations = analysis.mutation.map((o) => o.name);
|
|
107
|
+
const subscriptions = analysis.subscription.map((o) => o.name);
|
|
98
108
|
const lines = [
|
|
99
109
|
`import type { TypedDocumentNode } from "@graphql-typed-document-node/core";`,
|
|
100
110
|
`import * as ops from "#graphql/operations";`,
|
|
@@ -102,11 +112,11 @@ function generateRegistryByTypeSource(analysis) {
|
|
|
102
112
|
`type ResultOf<T> = T extends { __apiType?: (variables: infer _) => infer R } ? R : never;`,
|
|
103
113
|
`type VariablesOf<T> = T extends { __apiType?: (variables: infer V) => infer _ } ? V : never;`
|
|
104
114
|
];
|
|
105
|
-
if (
|
|
115
|
+
if (queries.length > 0) {
|
|
106
116
|
lines.push(
|
|
107
117
|
``,
|
|
108
118
|
`export const queries = {`,
|
|
109
|
-
...
|
|
119
|
+
...queries.map((name) => ` ${name}: ops.${name}Document,`),
|
|
110
120
|
`} as const;`
|
|
111
121
|
);
|
|
112
122
|
} else {
|
|
@@ -117,11 +127,11 @@ function generateRegistryByTypeSource(analysis) {
|
|
|
117
127
|
`export type QueryResult<N extends QueryName> = ResultOf<(typeof queries)[N]>;`,
|
|
118
128
|
`export type QueryVariables<N extends QueryName> = VariablesOf<(typeof queries)[N]>;`
|
|
119
129
|
);
|
|
120
|
-
if (
|
|
130
|
+
if (mutations.length > 0) {
|
|
121
131
|
lines.push(
|
|
122
132
|
``,
|
|
123
133
|
`export const mutations = {`,
|
|
124
|
-
...
|
|
134
|
+
...mutations.map((name) => ` ${name}: ops.${name}Document,`),
|
|
125
135
|
`} as const;`
|
|
126
136
|
);
|
|
127
137
|
} else {
|
|
@@ -132,11 +142,11 @@ function generateRegistryByTypeSource(analysis) {
|
|
|
132
142
|
`export type MutationResult<N extends MutationName> = ResultOf<(typeof mutations)[N]>;`,
|
|
133
143
|
`export type MutationVariables<N extends MutationName> = VariablesOf<(typeof mutations)[N]>;`
|
|
134
144
|
);
|
|
135
|
-
if (
|
|
145
|
+
if (subscriptions.length > 0) {
|
|
136
146
|
lines.push(
|
|
137
147
|
``,
|
|
138
148
|
`export const subscriptions = {`,
|
|
139
|
-
...
|
|
149
|
+
...subscriptions.map((name) => ` ${name}: ops.${name}Document,`),
|
|
140
150
|
`} as const;`
|
|
141
151
|
);
|
|
142
152
|
} else {
|
|
@@ -164,16 +174,6 @@ function formatDefinitions(defs) {
|
|
|
164
174
|
};
|
|
165
175
|
return defs.map((def) => `${colorOf(def)}${def.name}${reset}`).join(`${dim} / ${reset}`);
|
|
166
176
|
}
|
|
167
|
-
async function loadGraphQLSchema(schemaPath) {
|
|
168
|
-
const { createJiti } = await import('jiti');
|
|
169
|
-
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
170
|
-
const module = await jiti.import(schemaPath);
|
|
171
|
-
if (!module.schema) {
|
|
172
|
-
throw new Error(`${schemaPath} must export a 'schema' variable`);
|
|
173
|
-
}
|
|
174
|
-
const { printSchema, lexicographicSortSchema } = await import('graphql');
|
|
175
|
-
return printSchema(lexicographicSortSchema(module.schema));
|
|
176
|
-
}
|
|
177
177
|
async function runCodegen(options) {
|
|
178
178
|
const { sdl, documents, operationsFile } = options;
|
|
179
179
|
if (documents.length === 0) {
|
|
@@ -219,13 +219,17 @@ const module$1 = defineNuxtModule({
|
|
|
219
219
|
defaults: {
|
|
220
220
|
endpoint: "/api/graphql",
|
|
221
221
|
codegen: {
|
|
222
|
-
enabled: true,
|
|
223
222
|
pattern: "**/*.gql",
|
|
224
223
|
schemaOutput: "server/graphql/schema.graphql"
|
|
225
224
|
}
|
|
226
225
|
},
|
|
227
226
|
async setup(options, nuxt) {
|
|
228
227
|
const { resolve } = createResolver(import.meta.url);
|
|
228
|
+
if (options.endpoint) {
|
|
229
|
+
if (!options.endpoint.startsWith("/")) {
|
|
230
|
+
logger.warn("GraphQL endpoint should start with '/' (e.g., '/api/graphql')");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
229
233
|
const { rootDir, serverDir } = nuxt.options;
|
|
230
234
|
const layerDirs = [
|
|
231
235
|
...getLayerDirectories(nuxt),
|
|
@@ -250,51 +254,54 @@ const module$1 = defineNuxtModule({
|
|
|
250
254
|
logger.success(`GraphQL Yoga ready at ${cyan}${url.replace(/\/$/, "")}${endpoint}${reset}`);
|
|
251
255
|
});
|
|
252
256
|
nuxt.options.runtimeConfig.public.graphql = { endpoint };
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
257
|
+
const codegenPattern = options.codegen?.pattern ?? "**/*.gql";
|
|
258
|
+
const graphqlrcFile = join(rootDir, ".graphqlrc");
|
|
259
|
+
const operationsFile = join(nuxt.options.buildDir, "graphql/operations.ts");
|
|
260
|
+
const registryFile = join(nuxt.options.buildDir, "graphql/registry.ts");
|
|
261
|
+
nuxt.options.alias["#graphql/operations"] = operationsFile;
|
|
262
|
+
nuxt.options.alias["#graphql/registry"] = registryFile;
|
|
263
|
+
const schemaOutput = options.codegen?.schemaOutput ?? "server/graphql/schema.graphql";
|
|
264
|
+
if (schemaOutput) {
|
|
265
|
+
if (!schemaOutput.endsWith(".graphql")) {
|
|
266
|
+
logger.warn(`Schema output '${schemaOutput}' should have .graphql extension.`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const schemaFile = join(rootDir, schemaOutput);
|
|
270
|
+
const generate = async () => {
|
|
271
|
+
const [sdl, documents] = await Promise.all([
|
|
272
|
+
loadGraphQLSchema(schemaPath),
|
|
273
|
+
findMultipleFiles(layerRootDirs, codegenPattern)
|
|
274
|
+
]);
|
|
275
|
+
const docs = documents.map((document) => ({ path: document, content: readFileSync(document, "utf-8") }));
|
|
276
|
+
const analysis = analyzeGraphQLDocuments(docs);
|
|
277
|
+
for (const doc of docs) {
|
|
278
|
+
const relativePath = doc.path.startsWith(rootDir) ? doc.path.slice(rootDir.length + 1) : doc.path;
|
|
279
|
+
const defs = analysis.byFile.get(doc.path) ?? [];
|
|
280
|
+
logger.info(`${cyan}${relativePath}${reset} [${formatDefinitions(defs)}]`);
|
|
281
|
+
}
|
|
282
|
+
await runCodegen({ sdl, documents, operationsFile });
|
|
283
|
+
if (writeFileIfChanged(schemaFile, sdl)) {
|
|
284
|
+
logger.info(`GraphQL schema saved to ${cyan}${schemaOutput}${reset}`);
|
|
285
|
+
}
|
|
286
|
+
const config = JSON.stringify({ schema: relative(rootDir, schemaFile), documents: codegenPattern }, null, 2);
|
|
287
|
+
if (writeFileIfChanged(graphqlrcFile, config)) {
|
|
288
|
+
logger.info(`GraphQL config saved to ${cyan}.graphqlrc${reset}`);
|
|
289
|
+
}
|
|
290
|
+
if (writeFileIfChanged(registryFile, generateRegistryByTypeSource(analysis.operationsByType))) {
|
|
291
|
+
logger.info(`GraphQL registry saved to ${cyan}${relative(rootDir, registryFile)}${reset}`);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
nuxt.hook("prepare:types", async ({ references }) => {
|
|
295
|
+
await generate();
|
|
296
|
+
if (existsSync(operationsFile)) references.push({ path: operationsFile });
|
|
297
|
+
if (existsSync(registryFile)) references.push({ path: registryFile });
|
|
298
|
+
});
|
|
299
|
+
if (nuxt.options.dev) {
|
|
300
|
+
nuxt.hook("builder:watch", async (event, path) => {
|
|
301
|
+
if (path.endsWith(".gql")) {
|
|
302
|
+
await generate();
|
|
282
303
|
}
|
|
283
|
-
};
|
|
284
|
-
nuxt.hook("prepare:types", async ({ references }) => {
|
|
285
|
-
await generate();
|
|
286
|
-
if (existsSync(operationsFile)) references.push({ path: operationsFile });
|
|
287
|
-
if (existsSync(registryFile)) references.push({ path: registryFile });
|
|
288
304
|
});
|
|
289
|
-
if (nuxt.options.dev) {
|
|
290
|
-
nuxt.hook("builder:watch", async (event, path) => {
|
|
291
|
-
if (path.endsWith(".gql")) {
|
|
292
|
-
await generate();
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
nuxt.options.alias["#graphql/operations"] = operationsFile;
|
|
297
|
-
nuxt.options.alias["#graphql/registry"] = registryFile;
|
|
298
305
|
}
|
|
299
306
|
addImportsDir(resolve("./runtime/composables"));
|
|
300
307
|
addPlugin(resolve("./runtime/plugins/graphql"));
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { type Ref } from "vue";
|
|
2
1
|
import { type MutationName, type MutationResult, type MutationVariables } from "#graphql/registry";
|
|
3
|
-
type IsEmptyObject
|
|
2
|
+
import type { IsEmptyObject } from "../utils/helpers.js";
|
|
4
3
|
export declare function useGraphQLMutation<N extends MutationName>(operationName: N): {
|
|
5
|
-
mutate: (...args: IsEmptyObject<MutationVariables<N>> extends true ? [variables?: MutationVariables<N>] : [variables: MutationVariables<N>]) => Promise<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
mutate: (...args: IsEmptyObject<MutationVariables<N>> extends true ? [variables?: MutationVariables<N>] : [variables: MutationVariables<N>]) => Promise<{
|
|
5
|
+
data: MutationResult<N> | null;
|
|
6
|
+
error: Error | null;
|
|
7
|
+
}>;
|
|
8
|
+
pending: import("vue").Ref<boolean, boolean>;
|
|
9
9
|
};
|
|
10
|
-
export {};
|
|
@@ -4,22 +4,18 @@ import { mutations } from "#graphql/registry";
|
|
|
4
4
|
export function useGraphQLMutation(operationName) {
|
|
5
5
|
const document = mutations[operationName];
|
|
6
6
|
const { request } = useGraphQL();
|
|
7
|
-
const data = ref(null);
|
|
8
|
-
const error = ref(null);
|
|
9
7
|
const pending = ref(false);
|
|
10
8
|
async function mutate(...args) {
|
|
11
9
|
pending.value = true;
|
|
12
|
-
error.value = null;
|
|
13
10
|
try {
|
|
14
11
|
const result = await request(document, args[0]);
|
|
15
|
-
data
|
|
16
|
-
return result;
|
|
12
|
+
return { data: result, error: null };
|
|
17
13
|
} catch (e) {
|
|
18
|
-
error
|
|
19
|
-
|
|
14
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
15
|
+
return { data: null, error };
|
|
20
16
|
} finally {
|
|
21
17
|
pending.value = false;
|
|
22
18
|
}
|
|
23
19
|
}
|
|
24
|
-
return { mutate,
|
|
20
|
+
return { mutate, pending };
|
|
25
21
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AsyncData, AsyncDataOptions } from "#app";
|
|
2
2
|
import { type QueryName, type QueryResult, type QueryVariables } from "#graphql/registry";
|
|
3
|
-
type IsEmptyObject
|
|
3
|
+
import type { IsEmptyObject } from "../utils/helpers.js";
|
|
4
4
|
export declare function useGraphQLQuery<N extends QueryName>(operationName: N, ...args: IsEmptyObject<QueryVariables<N>> extends true ? [variables?: QueryVariables<N>, opts?: AsyncDataOptions<QueryResult<N>>] : [variables: QueryVariables<N>, opts?: AsyncDataOptions<QueryResult<N>>]): AsyncData<QueryResult<N>, Error | null>;
|
|
5
|
-
export {};
|
|
@@ -6,6 +6,6 @@ export function useGraphQLQuery(operationName, ...args) {
|
|
|
6
6
|
const document = queries[operationName];
|
|
7
7
|
const [variables, opts] = args;
|
|
8
8
|
const { request } = useGraphQL();
|
|
9
|
-
const key = `
|
|
9
|
+
const key = `graphql:query:${operationName}:${hash(variables ?? {})}`;
|
|
10
10
|
return useAsyncData(key, () => request(document, variables), opts);
|
|
11
11
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type IsEmptyObject<T> = T extends Record<string, never> ? true : keyof T extends never ? true : false;
|
|
File without changes
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createYoga } from "graphql-yoga";
|
|
2
|
-
import { defineEventHandler, toWebRequest, sendWebResponse } from "h3";
|
|
2
|
+
import { defineEventHandler, toWebRequest, sendWebResponse, createError } from "h3";
|
|
3
3
|
import { schema } from "#graphql/schema";
|
|
4
4
|
import { createContext } from "#graphql/context";
|
|
5
|
+
import { useLogger } from "@nuxt/kit";
|
|
5
6
|
|
|
6
7
|
let yoga = null;
|
|
7
8
|
|
|
@@ -11,14 +12,23 @@ function getYoga() {
|
|
|
11
12
|
schema,
|
|
12
13
|
graphqlEndpoint: "{{endpoint}}",
|
|
13
14
|
fetchAPI: globalThis,
|
|
15
|
+
graphiql: process.env.NODE_ENV !== "production",
|
|
14
16
|
});
|
|
15
17
|
}
|
|
16
18
|
return yoga;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export default defineEventHandler(async (event) => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const logger = useLogger();
|
|
23
|
+
try {
|
|
24
|
+
const request = toWebRequest(event);
|
|
25
|
+
const context = await createContext(event);
|
|
26
|
+
const response = await getYoga().handleRequest(request, context);
|
|
27
|
+
return sendWebResponse(event, response);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
+
logger.error("GraphQL Server Error:", message);
|
|
32
|
+
throw createError({ statusCode: 500, message: "GraphQL server error" });
|
|
33
|
+
}
|
|
24
34
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lewebsimple/nuxt-graphql",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Opinionated Nuxt module for using GraphQL",
|
|
5
5
|
"repository": "lewebsimple/nuxt-graphql",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,17 +22,6 @@
|
|
|
22
22
|
"files": [
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
|
-
"scripts": {
|
|
26
|
-
"prepack": "nuxt-module-build build",
|
|
27
|
-
"dev": "npm run dev:prepare && nuxi dev playground",
|
|
28
|
-
"dev:build": "nuxi build playground",
|
|
29
|
-
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
30
|
-
"release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
|
|
31
|
-
"lint": "eslint .",
|
|
32
|
-
"test": "vitest run",
|
|
33
|
-
"test:watch": "vitest watch",
|
|
34
|
-
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
|
|
35
|
-
},
|
|
36
25
|
"dependencies": {
|
|
37
26
|
"@graphql-codegen/cli": "^5.0.7",
|
|
38
27
|
"@graphql-codegen/typed-document-node": "^5.1.2",
|
|
@@ -42,7 +31,7 @@
|
|
|
42
31
|
"@nuxt/kit": "^4.2.2",
|
|
43
32
|
"graphql": "^16.12.0",
|
|
44
33
|
"graphql-request": "^7.4.0",
|
|
45
|
-
"graphql-yoga": "^5.
|
|
34
|
+
"graphql-yoga": "^5.18.0",
|
|
46
35
|
"jiti": "^2.6.1",
|
|
47
36
|
"ohash": "^2.0.11",
|
|
48
37
|
"tinyglobby": "^0.2.15"
|
|
@@ -59,10 +48,25 @@
|
|
|
59
48
|
"eslint": "^9.39.2",
|
|
60
49
|
"nuxt": "^4.2.2",
|
|
61
50
|
"typescript": "~5.9.3",
|
|
62
|
-
"vitest": "^4.0.
|
|
63
|
-
"vue-tsc": "^3.1
|
|
51
|
+
"vitest": "^4.0.16",
|
|
52
|
+
"vue-tsc": "^3.2.1"
|
|
64
53
|
},
|
|
65
54
|
"publishConfig": {
|
|
66
55
|
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"changlog": {
|
|
58
|
+
"types": {
|
|
59
|
+
"chore": false
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"dev": "npm run dev:prepare && nuxi dev playground",
|
|
64
|
+
"dev:build": "nuxi build playground",
|
|
65
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
66
|
+
"release": "npm run lint && npm run test && npm run prepack && changelogen --release --push && npm publish",
|
|
67
|
+
"lint": "eslint .",
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"test:watch": "vitest watch",
|
|
70
|
+
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
|
|
67
71
|
}
|
|
68
72
|
}
|