@dxup/nuxt 0.5.1 → 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.
- package/README.md +0 -2
- package/dist/languages/named-layout-slots.cjs +8 -2
- package/dist/module.mjs +55 -59
- package/dist/runtime/layouts.d.mts +3 -20
- package/dist/runtime/layouts.mjs +23 -38
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -89,8 +89,6 @@ Write top-level named slots in your pages:
|
|
|
89
89
|
|
|
90
90
|
And them will be forwarded to the active layout automatically.
|
|
91
91
|
|
|
92
|
-
Due to design limitations, dynamic slots are currently not supported.
|
|
93
|
-
|
|
94
92
|
### 4. nitroRoutes
|
|
95
93
|
|
|
96
94
|
Go to definition for nitro routes in data fetching methods.
|
|
@@ -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"
|
|
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/
|
|
99
|
-
const
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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.
|
|
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
|
-
|
|
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,37 +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
|
|
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");
|
|
184
179
|
}
|
|
185
180
|
});
|
|
186
181
|
addTypeTemplate({
|
|
187
182
|
filename: "dxup/layouts.d.ts",
|
|
188
183
|
getContents({ app }) {
|
|
184
|
+
const currentDir = join(nuxt.options.buildDir, "dxup");
|
|
189
185
|
return `
|
|
190
186
|
export interface Layouts {
|
|
191
|
-
${Object.values(app.layouts).map((layout) => `
|
|
187
|
+
${Object.values(app.layouts).map((layout) => ` ${genObjectKey(layout.name)}: ${genInlineTypeImport(relative(currentDir, layout.file))};`).join("\n")}
|
|
192
188
|
}
|
|
193
189
|
`.trimStart();
|
|
194
190
|
}
|
|
195
191
|
});
|
|
196
|
-
addBuildPlugin(
|
|
197
|
-
|
|
192
|
+
addBuildPlugin(TransformPlugins({
|
|
193
|
+
layoutDirs,
|
|
194
|
+
pageDirs,
|
|
198
195
|
sourcemap: !!nuxt.options.sourcemap.client
|
|
199
196
|
}));
|
|
200
|
-
addBuildPlugin(TransformLayoutPlugin({ sourcemap: !!nuxt.options.sourcemap.client }));
|
|
201
197
|
}
|
|
202
198
|
//#endregion
|
|
203
199
|
//#region src/module/index.ts
|
|
@@ -220,7 +216,7 @@ var module_default = defineNuxtModule().with({
|
|
|
220
216
|
async setup(options, nuxt) {
|
|
221
217
|
const pluginsTs = [{ name: "@dxup/nuxt" }];
|
|
222
218
|
const pluginsVue = [];
|
|
223
|
-
if (options.features.namedLayoutSlots) setup(nuxt, pluginsVue);
|
|
219
|
+
if (options.features.namedLayoutSlots) await setup(nuxt, pluginsVue);
|
|
224
220
|
if (options.features.unimport) pluginsTs.unshift({ name: "@dxup/unimport" });
|
|
225
221
|
append(pluginsTs, nuxt.options, "typescript", "tsConfig", "compilerOptions");
|
|
226
222
|
append(pluginsTs, nuxt.options.nitro, "typescript", "tsConfig", "compilerOptions");
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import { ShallowRef, Slots } from "vue";
|
|
2
|
-
|
|
3
1
|
//#region src/module/named-layout-slots/runtime/layouts.d.ts
|
|
4
|
-
|
|
5
|
-
slots: ShallowRef<Slots>;
|
|
6
|
-
set: (slots: Slots) => void;
|
|
7
|
-
waitFor: (name: string) => Promise<void>;
|
|
8
|
-
}
|
|
9
|
-
declare function provideLayoutSlots(): LayoutSlotsRegistry;
|
|
2
|
+
declare const _default: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
|
|
10
3
|
declare const LayoutSlot: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
11
4
|
name: {
|
|
12
5
|
type: StringConstructor;
|
|
13
6
|
required: true;
|
|
14
7
|
};
|
|
15
|
-
props: {
|
|
16
|
-
type: ObjectConstructor;
|
|
17
|
-
default: () => {};
|
|
18
|
-
};
|
|
19
8
|
}>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
20
9
|
[key: string]: any;
|
|
21
10
|
}>[] | undefined, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -23,13 +12,7 @@ declare const LayoutSlot: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
23
12
|
type: StringConstructor;
|
|
24
13
|
required: true;
|
|
25
14
|
};
|
|
26
|
-
|
|
27
|
-
type: ObjectConstructor;
|
|
28
|
-
default: () => {};
|
|
29
|
-
};
|
|
30
|
-
}>> & Readonly<{}>, {
|
|
31
|
-
props: Record<string, any>;
|
|
32
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
15
|
+
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
33
16
|
declare const LayoutSlotsForward: import("vue").DefineSetupFnComponent<Record<string, any>, {}, {}, Record<string, any> & {}, import("vue").PublicProps>;
|
|
34
17
|
//#endregion
|
|
35
|
-
export { LayoutSlot, LayoutSlotsForward,
|
|
18
|
+
export { LayoutSlot, LayoutSlotsForward, _default as default };
|
package/dist/runtime/layouts.mjs
CHANGED
|
@@ -1,53 +1,38 @@
|
|
|
1
|
-
import { defineComponent, inject, provide, shallowRef } from "vue";
|
|
1
|
+
import { defineComponent, h, inject, provide, shallowRef } from "vue";
|
|
2
|
+
import { NuxtLayout } from "#build/dxup/layouts.mjs";
|
|
2
3
|
//#region src/module/named-layout-slots/runtime/layouts.ts
|
|
3
4
|
const injectionKey = Symbol();
|
|
4
|
-
|
|
5
|
+
var layouts_default = defineComponent((props, ctx) => {
|
|
5
6
|
const slots = shallowRef({});
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
let resolveReady;
|
|
8
|
+
provide(injectionKey, {
|
|
8
9
|
slots,
|
|
10
|
+
ready: new Promise((resolve) => {
|
|
11
|
+
resolveReady = resolve;
|
|
12
|
+
}),
|
|
9
13
|
set(value) {
|
|
10
14
|
slots.value = value;
|
|
11
|
-
|
|
12
|
-
const resolves = waiters.get(name);
|
|
13
|
-
if (!resolves?.length) continue;
|
|
14
|
-
waiters.delete(name);
|
|
15
|
-
for (const resolve of resolves) resolve();
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
waitFor(name) {
|
|
19
|
-
if (slots.value[name]) return Promise.resolve();
|
|
20
|
-
return new Promise((resolve) => {
|
|
21
|
-
let resolves = waiters.get(name);
|
|
22
|
-
if (!resolves) waiters.set(name, resolves = []);
|
|
23
|
-
resolves.push(resolve);
|
|
24
|
-
});
|
|
15
|
+
resolveReady?.();
|
|
25
16
|
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
17
|
+
});
|
|
18
|
+
return () => h(NuxtLayout, props, ctx.slots);
|
|
19
|
+
});
|
|
30
20
|
const LayoutSlot = defineComponent({
|
|
31
|
-
props: {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
setup(props) {
|
|
42
|
-
const registry = inject(injectionKey);
|
|
43
|
-
const render = () => registry.slots.value[props.name]?.(props.props);
|
|
44
|
-
if (import.meta.server && !registry.slots.value[props.name]) return registry.waitFor(props.name).then(() => render);
|
|
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);
|
|
45
29
|
return render;
|
|
46
30
|
}
|
|
47
31
|
});
|
|
48
32
|
const LayoutSlotsForward = defineComponent((props, ctx) => {
|
|
49
|
-
inject(injectionKey)
|
|
33
|
+
const { set } = inject(injectionKey);
|
|
34
|
+
set(ctx.slots);
|
|
50
35
|
return () => ctx.slots.default?.();
|
|
51
36
|
});
|
|
52
37
|
//#endregion
|
|
53
|
-
export { LayoutSlot, LayoutSlotsForward,
|
|
38
|
+
export { LayoutSlot, LayoutSlotsForward, layouts_default as default };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxup/nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.2",
|
|
5
5
|
"description": "TypeScript plugin for Nuxt",
|
|
6
6
|
"author": "KazariEX",
|
|
7
7
|
"license": "MIT",
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"chokidar": "^5.0.0",
|
|
26
26
|
"knitwork": "^1.3.0",
|
|
27
27
|
"magic-string": "^0.30.21",
|
|
28
|
-
"oxc-walker": "^1.0.0",
|
|
29
28
|
"pathe": "^2.0.3",
|
|
30
29
|
"tinyglobby": "^0.2.17",
|
|
31
30
|
"unplugin": "^3.0.0",
|