@dxup/nuxt 0.5.0 → 0.5.2

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.
@@ -20,8 +20,14 @@ const plugin = ({ modules: { typescript: ts, "@vue/compiler-dom": CompilerDOM },
20
20
  if (sfc.scriptSetup) visit(sfc.scriptSetup.ast);
21
21
  function visit(node) {
22
22
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "definePageMeta" && node.arguments.length && ts.isObjectLiteralExpression(node.arguments[0])) {
23
- for (const prop of node.arguments[0].properties) if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "layout" && ts.isStringLiteral(prop.initializer)) {
24
- layoutName = prop.initializer.text;
23
+ for (const prop of node.arguments[0].properties) if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && prop.name.text === "layout") {
24
+ if (ts.isStringLiteralLike(prop.initializer)) layoutName = prop.initializer.text;
25
+ else if (ts.isObjectLiteralExpression(prop.initializer)) {
26
+ for (const sub of prop.initializer.properties) if (ts.isPropertyAssignment(sub) && ts.isIdentifier(sub.name) && sub.name.text === "name" && ts.isStringLiteralLike(sub.initializer)) {
27
+ layoutName = sub.initializer.text;
28
+ break;
29
+ }
30
+ }
25
31
  break;
26
32
  }
27
33
  } else ts.forEachChild(node, visit);
package/dist/module.mjs CHANGED
@@ -8,7 +8,6 @@ import { genExport, genImport, genInlineTypeImport, genObjectKey } from "knitwor
8
8
  import { ElementTypes, NodeTypes, parse } from "@vue/compiler-dom";
9
9
  import MagicString from "magic-string";
10
10
  import { createUnplugin } from "unplugin";
11
- import { parseAndWalk } from "oxc-walker";
12
11
  //#region package.json
13
12
  var name = "@dxup/nuxt";
14
13
  //#endregion
@@ -94,72 +93,52 @@ function parseSFC(code) {
94
93
  template
95
94
  };
96
95
  }
96
+ function* forEachElementNode(node) {
97
+ if (node.type === NodeTypes.ROOT || node.type === NodeTypes.FOR || node.type === NodeTypes.IF_BRANCH) for (const child of node.children) yield* forEachElementNode(child);
98
+ else if (node.type === NodeTypes.ELEMENT) {
99
+ yield node;
100
+ for (const child of node.children) yield* forEachElementNode(child);
101
+ } else if (node.type === NodeTypes.IF) for (const branch of node.branches) yield* forEachElementNode(branch);
102
+ }
97
103
  //#endregion
98
- //#region src/module/named-layout-slots/plugins/transform-layout.ts
99
- const TransformLayoutPlugin = (options) => createUnplugin(() => ({
104
+ //#region src/module/named-layout-slots/transform.ts
105
+ const TransformPlugins = (options) => createUnplugin(() => [{
100
106
  name: name + ":transform-layout",
101
107
  enforce: "pre",
102
108
  transformInclude: isVue,
103
- transform: {
104
- filter: { code: /<(?:nuxt-layout|NuxtLayout)/ },
105
- handler(code) {
106
- const { scriptSetup, template } = parseSFC(code);
107
- const layout = template?.children.find((node) => node.type === NodeTypes.ELEMENT && (node.tag === "nuxt-layout" || node.tag === "NuxtLayout"));
108
- if (!layout?.children.length) return;
109
- const s = new MagicString(code);
110
- const prefix = "\n" + genImport("#build/dxup/layouts.mjs", ["provideLayoutSlots"]);
111
- const suffix = `\nconst __dxup_layoutSlots = provideLayoutSlots();\n`;
112
- if (scriptSetup) {
113
- s.appendLeft(scriptSetup.innerLoc.start.offset, prefix);
114
- s.appendLeft(scriptSetup.innerLoc.end.offset, suffix);
115
- } else s.prepend(`<script setup>${prefix + suffix}<\/script>\n\n`);
116
- s.appendLeft(layout.children.at(-1).loc.end.offset, `
117
- <template v-for="name in $route.meta.layoutSlots ?? []" :key="name" #[name]="props">
118
- <component :is="() => __dxup_layoutSlots[name]?.(props)"/>
119
- </template>`);
120
- return {
121
- code: s.toString(),
122
- map: options.sourcemap ? s.generateMap({ hires: true }) : void 0
123
- };
124
- }
109
+ transform(code, id) {
110
+ if (!options.layoutDirs.some((dir) => isInDir(id, dir))) return;
111
+ const { scriptSetup, template } = parseSFC(code);
112
+ if (!template) return;
113
+ const slots = [];
114
+ for (const node of forEachElementNode(template)) if (node.tagType === ElementTypes.SLOT && node.props.length && node.props.every((prop) => prop.name !== "name" || prop.type !== NodeTypes.ATTRIBUTE || prop.value && prop.value.content !== "default")) slots.push(node);
115
+ if (!slots.length) return;
116
+ const s = new MagicString(code);
117
+ const imports = genImport("#build/dxup/layouts.mjs", ["LayoutSlot"]);
118
+ if (scriptSetup) {
119
+ const start = scriptSetup.innerLoc.start.offset;
120
+ s.appendLeft(start, `\n${imports}\n`);
121
+ } else s.prepend(`<script setup>\n${imports}\n<\/script>\n\n`);
122
+ for (const slot of slots) for (const offset of /* @__PURE__ */ new Set([slot.loc.start.offset + slot.loc.source.indexOf("slot"), slot.loc.start.offset + slot.loc.source.lastIndexOf("slot")])) s.overwrite(offset, offset + 4, "LayoutSlot");
123
+ return {
124
+ code: s.toString(),
125
+ map: options.sourcemap ? s.generateMap({ hires: true }) : void 0
126
+ };
125
127
  }
126
- }));
127
- //#endregion
128
- //#region src/module/named-layout-slots/plugins/transform-page.ts
129
- const TransformPagePlugin = (options) => createUnplugin(() => ({
128
+ }, {
130
129
  name: name + ":transform-page",
131
130
  enforce: "pre",
132
131
  transformInclude: isVue,
133
132
  transform(code, id) {
134
- if (!options.dirs.some((dir) => isInDir(id, dir))) return;
133
+ if (!options.pageDirs.some((dir) => isInDir(id, dir))) return;
135
134
  const { scriptSetup, template } = parseSFC(code);
136
135
  if (!template) return;
137
- const slots = [];
138
- for (const node of template.children) {
139
- if (node.type !== NodeTypes.ELEMENT || node.tagType !== ElementTypes.TEMPLATE) continue;
140
- const dir = node.props.find((prop) => prop.type === NodeTypes.DIRECTIVE && prop.name === "slot");
141
- if (dir?.arg?.type === NodeTypes.SIMPLE_EXPRESSION && dir.arg.isStatic && dir.arg.content !== "" && dir.arg.content !== "default") slots.push(dir.arg.content);
142
- }
143
- if (!slots.length) return;
144
136
  const s = new MagicString(code);
145
137
  const imports = genImport("#build/dxup/layouts.mjs", ["LayoutSlotsForward"]);
146
- const expression = `layoutSlots: [${slots.map((slot) => JSON.stringify(slot)).join(", ")}],\n`;
147
138
  if (scriptSetup) {
148
- let meta;
149
- parseAndWalk(scriptSetup.innerLoc.source, id, {
150
- parseOptions: { lang: scriptSetup.props.find((prop) => prop.type === NodeTypes.ATTRIBUTE && prop.name === "lang")?.value?.content ?? "ts" },
151
- enter(node) {
152
- if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "definePageMeta" && node.arguments[0]?.type === "ObjectExpression") {
153
- meta = node.arguments[0];
154
- this.skip();
155
- }
156
- }
157
- });
158
139
  const start = scriptSetup.innerLoc.start.offset;
159
140
  s.appendLeft(start, `\n${imports}\n`);
160
- if (meta) s.appendLeft(meta.properties[0].start + start, expression);
161
- else s.appendLeft(scriptSetup.innerLoc.start.offset, `\ndefinePageMeta({\n${expression}});\n`);
162
- } else s.prepend(`<script setup>\n${imports}\ndefinePageMeta({\n${expression}});\n<\/script>\n\n`);
141
+ } else s.prepend(`<script setup>\n${imports}\n<\/script>\n\n`);
163
142
  s.appendLeft(template.innerLoc.start.offset, `<LayoutSlotsForward>`);
164
143
  s.appendLeft(template.innerLoc.end.offset, "</LayoutSlotsForward>");
165
144
  return {
@@ -167,56 +146,54 @@ const TransformPagePlugin = (options) => createUnplugin(() => ({
167
146
  map: options.sourcemap ? s.generateMap({ hires: true }) : void 0
168
147
  };
169
148
  }
170
- }));
149
+ }]);
171
150
  //#endregion
172
151
  //#region src/module/named-layout-slots/module.ts
173
- function setup(nuxt, pluginsVue) {
152
+ async function setup(nuxt, pluginsVue) {
174
153
  const resolver = createResolver(import.meta.url);
154
+ const layoutDirs = nuxt.options._layers.map((layer) => join(layer.config.srcDir, layer.config.dir?.layouts ?? "layouts"));
175
155
  const pageDirs = nuxt.options._layers.map((layer) => join(layer.config.srcDir, layer.config.dir?.pages ?? "pages"));
176
156
  pluginsVue.push({
177
157
  name: "@dxup/nuxt/languages/named-layout-slots.cjs",
178
158
  options: { dirs: pageDirs }
179
159
  });
160
+ nuxt.hook("components:extend", (components) => {
161
+ for (const comp of components) if (comp.pascalName === "NuxtLayout") {
162
+ comp.declarationPath = comp.filePath;
163
+ comp.filePath = join(nuxt.options.buildDir, "dxup/layouts.mjs");
164
+ break;
165
+ }
166
+ });
167
+ const layoutPath = join(await resolver.resolvePath("nuxt", { cwd: nuxt.options.rootDir }), "../app/components/nuxt-layout.js");
180
168
  addTemplate({
181
169
  filename: "dxup/layouts.mjs",
182
170
  getContents() {
183
- return `
184
- ${genImport("vue", [
185
- "inject",
186
- "provide",
187
- "shallowRef"
188
- ])}
189
- ${genExport(resolver.resolve("components/forward"), [{
190
- name: "default",
191
- as: "LayoutSlotsForward"
192
- }])}
193
- const injectionKey = Symbol();
194
- export function provideLayoutSlots() {
195
- const slots = shallowRef({});
196
- provide(injectionKey, slots);
197
- return slots;
198
- }
199
- export function injectLayoutSlots() {
200
- return inject(injectionKey);
201
- }
202
- `.trimStart();
171
+ return [
172
+ genExport(resolver.resolve("runtime/layouts.mjs"), "*"),
173
+ genExport(resolver.resolve("runtime/layouts.mjs"), ["default"]),
174
+ genExport(layoutPath, [{
175
+ name: "default",
176
+ as: "NuxtLayout"
177
+ }])
178
+ ].join("\n");
203
179
  }
204
180
  });
205
181
  addTypeTemplate({
206
182
  filename: "dxup/layouts.d.ts",
207
183
  getContents({ app }) {
184
+ const currentDir = join(nuxt.options.buildDir, "dxup");
208
185
  return `
209
186
  export interface Layouts {
210
- ${Object.values(app.layouts).map((layout) => ` ${genObjectKey(layout.name)}: ${genInlineTypeImport(layout.file)};`).join("\n")}
187
+ ${Object.values(app.layouts).map((layout) => ` ${genObjectKey(layout.name)}: ${genInlineTypeImport(relative(currentDir, layout.file))};`).join("\n")}
211
188
  }
212
189
  `.trimStart();
213
190
  }
214
191
  });
215
- addBuildPlugin(TransformPagePlugin({
216
- dirs: pageDirs,
192
+ addBuildPlugin(TransformPlugins({
193
+ layoutDirs,
194
+ pageDirs,
217
195
  sourcemap: !!nuxt.options.sourcemap.client
218
196
  }));
219
- addBuildPlugin(TransformLayoutPlugin({ sourcemap: !!nuxt.options.sourcemap.client }));
220
197
  }
221
198
  //#endregion
222
199
  //#region src/module/index.ts
@@ -239,7 +216,7 @@ var module_default = defineNuxtModule().with({
239
216
  async setup(options, nuxt) {
240
217
  const pluginsTs = [{ name: "@dxup/nuxt" }];
241
218
  const pluginsVue = [];
242
- if (options.features.namedLayoutSlots) setup(nuxt, pluginsVue);
219
+ if (options.features.namedLayoutSlots) await setup(nuxt, pluginsVue);
243
220
  if (options.features.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
244
221
  append(pluginsTs, nuxt.options, "typescript", "tsConfig", "compilerOptions");
245
222
  append(pluginsTs, nuxt.options.nitro, "typescript", "tsConfig", "compilerOptions");
@@ -0,0 +1,18 @@
1
+ //#region src/module/named-layout-slots/runtime/layouts.d.ts
2
+ declare const _default: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
3
+ declare const LayoutSlot: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
4
+ name: {
5
+ type: StringConstructor;
6
+ required: true;
7
+ };
8
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
9
+ [key: string]: any;
10
+ }>[] | undefined, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
11
+ name: {
12
+ type: StringConstructor;
13
+ required: true;
14
+ };
15
+ }>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
16
+ declare const LayoutSlotsForward: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
17
+ //#endregion
18
+ export { LayoutSlot, LayoutSlotsForward, _default as default };
@@ -0,0 +1,38 @@
1
+ import { defineComponent, h, inject, provide, shallowRef } from "vue";
2
+ import { NuxtLayout } from "#build/dxup/layouts.mjs";
3
+ //#region src/module/named-layout-slots/runtime/layouts.ts
4
+ const injectionKey = Symbol();
5
+ var layouts_default = defineComponent((props, ctx) => {
6
+ const slots = shallowRef({});
7
+ let resolveReady;
8
+ provide(injectionKey, {
9
+ slots,
10
+ ready: new Promise((resolve) => {
11
+ resolveReady = resolve;
12
+ }),
13
+ set(value) {
14
+ slots.value = value;
15
+ resolveReady?.();
16
+ }
17
+ });
18
+ return () => h(NuxtLayout, props, ctx.slots);
19
+ });
20
+ const LayoutSlot = defineComponent({
21
+ props: { name: {
22
+ type: String,
23
+ required: true
24
+ } },
25
+ setup(props, ctx) {
26
+ const { slots, ready } = inject(injectionKey);
27
+ const render = () => slots.value[props.name]?.(ctx.attrs);
28
+ if (import.meta.server && !slots.value[props.name]) return ready.then(() => render);
29
+ return render;
30
+ }
31
+ });
32
+ const LayoutSlotsForward = defineComponent((props, ctx) => {
33
+ const { set } = inject(injectionKey);
34
+ set(ctx.slots);
35
+ return () => ctx.slots.default?.();
36
+ });
37
+ //#endregion
38
+ export { LayoutSlot, LayoutSlotsForward, layouts_default as default };
@@ -172,12 +172,12 @@ var getDefinitionAndBoundSpan_exports = /* @__PURE__ */ __exportAll({
172
172
  postprocess: () => postprocess,
173
173
  preprocess: () => preprocess$1
174
174
  });
175
- const fetchFunctions = new Set([
175
+ const fetchFunctions = /* @__PURE__ */ new Set([
176
176
  "$fetch",
177
177
  "useFetch",
178
178
  "useLazyFetch"
179
179
  ]);
180
- const pageMetaKeys = new Set(["layout", "middleware"]);
180
+ const pageMetaKeys = /* @__PURE__ */ new Set(["layout", "middleware"]);
181
181
  function postprocess(context, language, getDefinitionAndBoundSpan) {
182
182
  const { ts } = context;
183
183
  return (...args) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dxup/nuxt",
3
3
  "type": "module",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "description": "TypeScript plugin for Nuxt",
6
6
  "author": "KazariEX",
7
7
  "license": "MIT",
@@ -11,7 +11,6 @@
11
11
  },
12
12
  "exports": {
13
13
  ".": "./dist/module.mjs",
14
- "./components/*": "./dist/components/*",
15
14
  "./languages/*": "./dist/languages/*",
16
15
  "./package.json": "./package.json"
17
16
  },
@@ -26,7 +25,6 @@
26
25
  "chokidar": "^5.0.0",
27
26
  "knitwork": "^1.3.0",
28
27
  "magic-string": "^0.30.21",
29
- "oxc-walker": "^1.0.0",
30
28
  "pathe": "^2.0.3",
31
29
  "tinyglobby": "^0.2.17",
32
30
  "unplugin": "^3.0.0",
@@ -1,4 +0,0 @@
1
- //#region src/module/named-layout-slots/components/forward.d.ts
2
- declare const _default: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
3
- //#endregion
4
- export { _default as default };
@@ -1,10 +0,0 @@
1
- import { defineComponent } from "vue";
2
- import { injectLayoutSlots } from "#build/dxup/layouts.mjs";
3
- //#region src/module/named-layout-slots/components/forward.ts
4
- var forward_default = defineComponent((props, ctx) => {
5
- const slots = injectLayoutSlots();
6
- slots.value = ctx.slots;
7
- return () => ctx.slots.default?.();
8
- });
9
- //#endregion
10
- export { forward_default as default };