nuxt-content-assets 1.1.0 → 1.2.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 +25 -19
- package/dist/module.d.ts +19 -1
- package/dist/module.json +4 -3
- package/dist/module.mjs +350 -189
- package/dist/runtime/assets/public.d.ts +41 -0
- package/dist/runtime/assets/public.mjs +111 -0
- package/dist/runtime/{services/sources.d.ts → assets/source.d.ts} +4 -4
- package/dist/runtime/{services/sources.mjs → assets/source.mjs} +4 -14
- package/dist/runtime/content/parsed.d.ts +5 -0
- package/dist/runtime/content/parsed.mjs +32 -0
- package/dist/runtime/content/plugin.mjs +65 -0
- package/dist/runtime/sockets/factory.d.ts +5 -1
- package/dist/runtime/sockets/factory.mjs +3 -10
- package/dist/runtime/sockets/plugin.d.ts +3 -0
- package/dist/runtime/sockets/plugin.mjs +31 -8
- package/dist/runtime/sockets/setup.d.ts +1 -1
- package/dist/runtime/sockets/setup.mjs +15 -2
- package/dist/runtime/utils/config.d.ts +11 -0
- package/dist/runtime/utils/config.mjs +12 -0
- package/dist/runtime/utils/content.d.ts +16 -0
- package/dist/runtime/utils/content.mjs +43 -0
- package/dist/runtime/utils/index.d.ts +2 -0
- package/dist/runtime/utils/index.mjs +2 -0
- package/dist/runtime/utils/object.d.ts +7 -3
- package/dist/runtime/utils/object.mjs +5 -2
- package/dist/runtime/utils/path.mjs +1 -1
- package/dist/types.d.ts +1 -5
- package/package.json +2 -4
- package/dist/runtime/config.d.ts +0 -2
- package/dist/runtime/config.mjs +0 -2
- package/dist/runtime/options.d.ts +0 -10
- package/dist/runtime/options.mjs +0 -18
- package/dist/runtime/plugin.mjs +0 -118
- package/dist/runtime/services/assets.d.ts +0 -32
- package/dist/runtime/services/assets.mjs +0 -42
- package/dist/runtime/services/index.d.ts +0 -3
- package/dist/runtime/services/index.mjs +0 -3
- package/dist/runtime/services/paths.d.ts +0 -8
- package/dist/runtime/services/paths.mjs +0 -26
- package/dist/runtime/sockets/composable.d.ts +0 -2
- package/dist/runtime/sockets/composable.mjs +0 -12
- /package/dist/runtime/{plugin.d.ts → content/plugin.d.ts} +0 -0
package/dist/module.mjs
CHANGED
|
@@ -2,14 +2,15 @@ import * as Fs from 'fs';
|
|
|
2
2
|
import * as Path from 'path';
|
|
3
3
|
import Path__default from 'path';
|
|
4
4
|
import { useNuxt, createResolver, defineNuxtModule, addPlugin } from '@nuxt/kit';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
5
|
+
import { visit, SKIP, CONTINUE } from 'unist-util-visit';
|
|
6
|
+
import { listen } from 'listhen';
|
|
7
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
8
8
|
import githubDriver from 'unstorage/drivers/github';
|
|
9
9
|
import fsDriver from 'unstorage/drivers/fs';
|
|
10
|
+
import { createStorage } from 'unstorage';
|
|
11
|
+
import getImageSize from 'image-size';
|
|
12
|
+
import debounce from 'debounce';
|
|
10
13
|
import 'ohash';
|
|
11
|
-
import { listen } from 'listhen';
|
|
12
|
-
import { WebSocketServer, WebSocket } from 'ws';
|
|
13
14
|
|
|
14
15
|
function matchTokens(value) {
|
|
15
16
|
let tokens = [];
|
|
@@ -33,22 +34,16 @@ function deKey(path) {
|
|
|
33
34
|
return path.replace(/^[^:]+:/, "");
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
const defaults = {
|
|
37
|
-
// inject image size into the rendered html
|
|
38
|
-
imageSize: "style",
|
|
39
|
-
// treat these extensions as content
|
|
40
|
-
contentExtensions: "md csv ya?ml json",
|
|
41
|
-
// output debug messages
|
|
42
|
-
debug: false
|
|
43
|
-
};
|
|
44
37
|
const extensions = {
|
|
45
38
|
// used to get image size
|
|
46
39
|
image: matchTokens("png jpg jpeg gif svg webp ico"),
|
|
47
40
|
// unused for now
|
|
48
41
|
media: matchTokens("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
|
|
49
42
|
};
|
|
50
|
-
function
|
|
51
|
-
|
|
43
|
+
function makeIgnores(extensions2) {
|
|
44
|
+
const matched = matchTokens(extensions2);
|
|
45
|
+
const ignored = matched.join("|");
|
|
46
|
+
return `[^:]+\\.(?!(${ignored})$)`;
|
|
52
47
|
}
|
|
53
48
|
|
|
54
49
|
function removeQuery(path) {
|
|
@@ -68,6 +63,73 @@ function isAsset(path) {
|
|
|
68
63
|
return !isArticle(path);
|
|
69
64
|
}
|
|
70
65
|
|
|
66
|
+
function walk(node, callback, filter) {
|
|
67
|
+
function visit(node2, callback2, parent, key) {
|
|
68
|
+
if (filter) {
|
|
69
|
+
const result = filter(node2, key);
|
|
70
|
+
if (result === false) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(node2)) {
|
|
75
|
+
node2.forEach((value, index) => {
|
|
76
|
+
visit(value, callback2, node2, index);
|
|
77
|
+
});
|
|
78
|
+
} else if (isObject(node2)) {
|
|
79
|
+
Object.keys(node2).forEach((key2) => {
|
|
80
|
+
visit(node2[key2], callback2, node2, key2);
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
callback2(node2, parent, key);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
visit(node, callback, { node }, "node");
|
|
87
|
+
}
|
|
88
|
+
function isObject(data) {
|
|
89
|
+
return data && typeof data === "object" && !Array.isArray(data);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function walkMeta(content, callback) {
|
|
93
|
+
walk(content, callback, (value, key) => !(String(key).startsWith("_") || key === "body"));
|
|
94
|
+
}
|
|
95
|
+
function walkBody(content, callback) {
|
|
96
|
+
visit(content.body, (node) => node.type === "element", (node) => {
|
|
97
|
+
const { tag, props } = node;
|
|
98
|
+
const excluded = tags.exclude.includes(tag);
|
|
99
|
+
if (excluded) {
|
|
100
|
+
return SKIP;
|
|
101
|
+
}
|
|
102
|
+
const included = tags.include.includes(tag);
|
|
103
|
+
if (included || !props) {
|
|
104
|
+
return CONTINUE;
|
|
105
|
+
}
|
|
106
|
+
callback(node);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const tags = {
|
|
110
|
+
// unlikely to contain assets
|
|
111
|
+
exclude: matchTokens({
|
|
112
|
+
container: "pre code code-inline",
|
|
113
|
+
formatting: "acronym abbr address bdi bdo big center cite del dfn font ins kbd mark meter progress q rp rt ruby s samp small strike sub sup time tt u var wbr",
|
|
114
|
+
headers: "h1 h2 h3 h4 h5 h6",
|
|
115
|
+
controls: "input textarea button select optgroup option label legend datalist output",
|
|
116
|
+
media: "map area canvas svg",
|
|
117
|
+
other: "style script noscript template",
|
|
118
|
+
empty: "hr br"
|
|
119
|
+
}),
|
|
120
|
+
// may contain assets
|
|
121
|
+
include: matchTokens({
|
|
122
|
+
content: "main header footer section article aside details dialog summary data object nav blockquote div span p",
|
|
123
|
+
table: "table caption th tr td thead tbody tfoot col colgroup",
|
|
124
|
+
media: "figcaption figure picture",
|
|
125
|
+
form: "form fieldset",
|
|
126
|
+
list: "ul ol li dir dl dt dd",
|
|
127
|
+
formatting: "strong b em i"
|
|
128
|
+
}),
|
|
129
|
+
// assets
|
|
130
|
+
assets: "a img audio source track video embed"
|
|
131
|
+
};
|
|
132
|
+
|
|
71
133
|
const label = "[content-assets]";
|
|
72
134
|
function log(...data) {
|
|
73
135
|
console.info(label, ...data);
|
|
@@ -82,6 +144,20 @@ ${items.map((item) => ` - ${item}`).join("\n")}
|
|
|
82
144
|
`);
|
|
83
145
|
}
|
|
84
146
|
|
|
147
|
+
function buildQuery(...expr) {
|
|
148
|
+
const output = expr.map((expr2) => expr2.replace(/^[?&]+|&+$/g, "")).filter((s) => s);
|
|
149
|
+
if (output.length) {
|
|
150
|
+
const [first, ...rest] = output;
|
|
151
|
+
const isParam = (expr2) => /^[^?]+=[^=]+$/.test(expr2);
|
|
152
|
+
return !isParam(first) ? rest.length > 0 ? first + (first.includes("?") ? "&" : "?") + rest.join("&") : first : "?" + output.join("&");
|
|
153
|
+
}
|
|
154
|
+
return "";
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function readFile(path, asJson = false) {
|
|
158
|
+
const text = Fs.readFileSync(path, { encoding: "utf8" });
|
|
159
|
+
return asJson ? JSON.parse(text) : text;
|
|
160
|
+
}
|
|
85
161
|
function writeFile(path, data) {
|
|
86
162
|
const text = typeof data === "object" ? JSON.stringify(data, null, " ") : String(data);
|
|
87
163
|
createFolder(Path.dirname(path));
|
|
@@ -109,51 +185,117 @@ function removeFolder(path) {
|
|
|
109
185
|
}
|
|
110
186
|
}
|
|
111
187
|
|
|
112
|
-
function
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
function getAssetSizes(srcAbs, hints) {
|
|
123
|
-
let width = void 0;
|
|
124
|
-
let height = void 0;
|
|
125
|
-
let ratio = void 0;
|
|
126
|
-
let query = void 0;
|
|
127
|
-
if (hints.length && isImage(srcAbs)) {
|
|
128
|
-
try {
|
|
129
|
-
const size = getImageSize(srcAbs);
|
|
130
|
-
if (hints.includes("attrs")) {
|
|
131
|
-
width = size.width;
|
|
132
|
-
height = size.height;
|
|
188
|
+
function createWebSocket() {
|
|
189
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
190
|
+
const serve = (req, socket = req.socket, head = "") => wss.handleUpgrade(req, socket, head, (client) => wss.emit("connection", client, req));
|
|
191
|
+
const broadcast = (data) => {
|
|
192
|
+
data = JSON.stringify(data);
|
|
193
|
+
for (const client of wss.clients) {
|
|
194
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
195
|
+
client.send(data);
|
|
133
196
|
}
|
|
134
|
-
|
|
135
|
-
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const handlers = [];
|
|
200
|
+
const addHandler = (callback) => {
|
|
201
|
+
handlers.push(callback);
|
|
202
|
+
};
|
|
203
|
+
wss.on("connection", (socket) => {
|
|
204
|
+
socket.addEventListener("message", (event) => {
|
|
205
|
+
let data;
|
|
206
|
+
try {
|
|
207
|
+
data = JSON.parse(event.data || "{}");
|
|
208
|
+
} catch (err) {
|
|
136
209
|
}
|
|
137
|
-
if (
|
|
138
|
-
|
|
210
|
+
if (data) {
|
|
211
|
+
handlers.forEach((callback) => callback(data));
|
|
139
212
|
}
|
|
140
|
-
}
|
|
141
|
-
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
return {
|
|
216
|
+
wss,
|
|
217
|
+
serve,
|
|
218
|
+
broadcast,
|
|
219
|
+
addHandler,
|
|
220
|
+
close: () => {
|
|
221
|
+
wss.clients.forEach((client) => client.close());
|
|
222
|
+
return new Promise((resolve) => wss.close(resolve));
|
|
142
223
|
}
|
|
143
|
-
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function makeChannelBroker(ws2) {
|
|
228
|
+
const handlers = [];
|
|
229
|
+
const broadcast = (channel, data) => {
|
|
230
|
+
ws2.broadcast({ channel, data });
|
|
231
|
+
};
|
|
232
|
+
const addHandler = (channel, callback) => {
|
|
233
|
+
handlers.push({ channel, callback });
|
|
234
|
+
};
|
|
235
|
+
ws2.addHandler(function(message) {
|
|
236
|
+
if (isObject(message)) {
|
|
237
|
+
const { channel } = message;
|
|
238
|
+
handlers.filter((handler) => handler.channel === channel || handler.channel === "*").forEach((handler) => handler.callback(message));
|
|
239
|
+
}
|
|
240
|
+
});
|
|
144
241
|
return {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
242
|
+
broadcast,
|
|
243
|
+
addHandler
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
const ws = createWebSocket();
|
|
247
|
+
const broker = makeChannelBroker(ws);
|
|
248
|
+
async function setupSocketServer(channel, handler) {
|
|
249
|
+
const nuxt = useNuxt();
|
|
250
|
+
nuxt.hook("nitro:init", async (nitro) => {
|
|
251
|
+
if (!nuxt._socketServer) {
|
|
252
|
+
const defaults = nuxt.options.runtimeConfig.content.watch.ws;
|
|
253
|
+
const port = defaults.port.port;
|
|
254
|
+
const { server, url } = await listen(() => "Nuxt Content Assets", {
|
|
255
|
+
hostname: defaults.hostname,
|
|
256
|
+
port: {
|
|
257
|
+
port: port + 1,
|
|
258
|
+
portRange: [
|
|
259
|
+
port + 1,
|
|
260
|
+
port + 40
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
showURL: false
|
|
264
|
+
});
|
|
265
|
+
nuxt._socketServer = server;
|
|
266
|
+
server.on("upgrade", ws.serve);
|
|
267
|
+
const wsUrl = url.replace("http", "ws");
|
|
268
|
+
log(`Websocket listening on "${wsUrl}"`);
|
|
269
|
+
nitro.options.runtimeConfig.public.sockets = {
|
|
270
|
+
wsUrl
|
|
271
|
+
};
|
|
272
|
+
nitro.hooks.hook("close", async () => {
|
|
273
|
+
await ws.close();
|
|
274
|
+
await server.close();
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
const instance = {
|
|
279
|
+
send(data) {
|
|
280
|
+
broker.broadcast(channel, data);
|
|
281
|
+
return this;
|
|
282
|
+
},
|
|
283
|
+
addHandler(callback) {
|
|
284
|
+
broker.addHandler(channel, callback);
|
|
285
|
+
return this;
|
|
286
|
+
}
|
|
149
287
|
};
|
|
288
|
+
if (handler) {
|
|
289
|
+
instance.addHandler(handler);
|
|
290
|
+
}
|
|
291
|
+
return instance;
|
|
150
292
|
}
|
|
151
293
|
|
|
152
294
|
function isAssetId(id) {
|
|
153
295
|
const path = toPath(id);
|
|
154
296
|
return !isExcluded(path) && isAsset(path);
|
|
155
297
|
}
|
|
156
|
-
function
|
|
298
|
+
function makeSourceStorage(source, key = "") {
|
|
157
299
|
const storage = createStorage();
|
|
158
300
|
const options = typeof source === "string" ? { driver: "fs", base: source } : source;
|
|
159
301
|
switch (options.driver) {
|
|
@@ -235,7 +377,7 @@ function makeSourceManager(key, source, publicPath, callback) {
|
|
|
235
377
|
}
|
|
236
378
|
return paths;
|
|
237
379
|
}
|
|
238
|
-
const storage =
|
|
380
|
+
const storage = makeSourceStorage(source, key);
|
|
239
381
|
storage.watch(onWatch);
|
|
240
382
|
return {
|
|
241
383
|
storage,
|
|
@@ -244,141 +386,159 @@ function makeSourceManager(key, source, publicPath, callback) {
|
|
|
244
386
|
};
|
|
245
387
|
}
|
|
246
388
|
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
const broadcast = (data) => {
|
|
254
|
-
data = JSON.stringify(data);
|
|
255
|
-
for (const client of wss.clients) {
|
|
256
|
-
if (client.readyState === WebSocket.OPEN) {
|
|
257
|
-
client.send(data);
|
|
258
|
-
}
|
|
389
|
+
function makeAssetsManager(publicPath) {
|
|
390
|
+
const indexKey = "assets.json";
|
|
391
|
+
const storage = makeSourceStorage(Path.join(publicPath, ".."));
|
|
392
|
+
storage.watch(async (event, key) => {
|
|
393
|
+
if (event === "update" && key === indexKey) {
|
|
394
|
+
await load();
|
|
259
395
|
}
|
|
260
|
-
};
|
|
261
|
-
const handlers = [];
|
|
262
|
-
const addHandler = (callback) => {
|
|
263
|
-
handlers.push(callback);
|
|
264
|
-
};
|
|
265
|
-
wss.on("connection", (socket) => {
|
|
266
|
-
socket.addEventListener("message", (event) => {
|
|
267
|
-
let data;
|
|
268
|
-
try {
|
|
269
|
-
data = JSON.parse(event.data || "{}");
|
|
270
|
-
} catch (err) {
|
|
271
|
-
}
|
|
272
|
-
if (data) {
|
|
273
|
-
handlers.forEach((callback) => callback(data));
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
396
|
});
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
397
|
+
const assets = {};
|
|
398
|
+
async function load() {
|
|
399
|
+
const data = await storage.getItem(indexKey);
|
|
400
|
+
Object.assign(assets, data || {});
|
|
401
|
+
}
|
|
402
|
+
const save = debounce(function() {
|
|
403
|
+
storage.setItem(indexKey, assets);
|
|
404
|
+
}, 50);
|
|
405
|
+
function resolveAsset(content, relAsset, registerContent = false) {
|
|
406
|
+
const srcDir = Path.dirname(content._file);
|
|
407
|
+
const srcAsset = Path.join(srcDir, relAsset);
|
|
408
|
+
const asset = assets[srcAsset];
|
|
409
|
+
if (asset && registerContent) {
|
|
410
|
+
const { _id } = content;
|
|
411
|
+
if (!asset.content.includes(_id)) {
|
|
412
|
+
asset.content.push(_id);
|
|
413
|
+
save();
|
|
414
|
+
}
|
|
285
415
|
}
|
|
416
|
+
return asset || {};
|
|
417
|
+
}
|
|
418
|
+
function setAsset(path) {
|
|
419
|
+
const { srcRel, srcAttr } = getAssetPaths(publicPath, path);
|
|
420
|
+
const { width, height } = getAssetSize(path);
|
|
421
|
+
const oldAsset = assets[srcRel];
|
|
422
|
+
const newAsset = {
|
|
423
|
+
srcAttr,
|
|
424
|
+
content: oldAsset?.content || [],
|
|
425
|
+
width,
|
|
426
|
+
height
|
|
427
|
+
};
|
|
428
|
+
assets[srcRel] = newAsset;
|
|
429
|
+
save();
|
|
430
|
+
return newAsset;
|
|
431
|
+
}
|
|
432
|
+
function getAsset(path) {
|
|
433
|
+
const { srcRel } = getAssetPaths(publicPath, path);
|
|
434
|
+
return srcRel ? { ...assets[srcRel] } : void 0;
|
|
435
|
+
}
|
|
436
|
+
function removeAsset(path) {
|
|
437
|
+
const { srcRel } = getAssetPaths(publicPath, path);
|
|
438
|
+
const asset = assets[srcRel];
|
|
439
|
+
if (asset) {
|
|
440
|
+
delete assets[srcRel];
|
|
441
|
+
save();
|
|
442
|
+
}
|
|
443
|
+
return asset;
|
|
444
|
+
}
|
|
445
|
+
void load();
|
|
446
|
+
return {
|
|
447
|
+
setAsset,
|
|
448
|
+
getAsset,
|
|
449
|
+
removeAsset,
|
|
450
|
+
resolveAsset
|
|
286
451
|
};
|
|
287
452
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
function makeChannelBroker(ws2) {
|
|
293
|
-
const handlers = [];
|
|
294
|
-
const broadcast = (channel, data) => {
|
|
295
|
-
ws2.broadcast({ channel, data });
|
|
296
|
-
};
|
|
297
|
-
const addHandler = (channel, callback) => {
|
|
298
|
-
handlers.push({ channel, callback });
|
|
299
|
-
};
|
|
300
|
-
ws2.addHandler(function(message) {
|
|
301
|
-
if (isObject(message)) {
|
|
302
|
-
const { channel } = message;
|
|
303
|
-
handlers.filter((handler) => handler.channel === channel || handler.channel === "*").forEach((handler) => handler.callback(message));
|
|
304
|
-
}
|
|
305
|
-
});
|
|
453
|
+
function getAssetPaths(srcDir, srcAbs) {
|
|
454
|
+
const srcRel = Path.relative(srcDir, srcAbs);
|
|
455
|
+
const srcAttr = "/" + srcRel;
|
|
306
456
|
return {
|
|
307
|
-
|
|
308
|
-
|
|
457
|
+
srcRel,
|
|
458
|
+
srcAttr
|
|
309
459
|
};
|
|
310
460
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
wsUrl
|
|
329
|
-
};
|
|
330
|
-
nitro.hooks.hook("close", async () => {
|
|
331
|
-
await ws.close();
|
|
332
|
-
await server.close();
|
|
333
|
-
});
|
|
461
|
+
function getAssetSize(srcAbs) {
|
|
462
|
+
if (isImage(srcAbs)) {
|
|
463
|
+
try {
|
|
464
|
+
return getImageSize(srcAbs);
|
|
465
|
+
} catch (err) {
|
|
466
|
+
warn(`could not read image "${srcAbs}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return {};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function rewriteContent(path, asset) {
|
|
473
|
+
const { parsed } = readFile(path, true);
|
|
474
|
+
const { srcAttr, width, height } = asset;
|
|
475
|
+
walkMeta(parsed, (value, parent, key) => {
|
|
476
|
+
if (value.startsWith(srcAttr)) {
|
|
477
|
+
parent[key] = parent[key].replace(/width=\d+&height=\d+/, `width=${width}&height=${height}`);
|
|
334
478
|
}
|
|
335
479
|
});
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
480
|
+
walkBody(parsed, function(node) {
|
|
481
|
+
const { tag, props } = node;
|
|
482
|
+
if (tag === "img" && props?.src?.startsWith(srcAttr)) {
|
|
483
|
+
props.src = buildQuery(srcAttr, `time=${Date.now()}`);
|
|
484
|
+
if (props.width) {
|
|
485
|
+
props.width = width;
|
|
486
|
+
}
|
|
487
|
+
if (props.height) {
|
|
488
|
+
props.height = height;
|
|
489
|
+
}
|
|
490
|
+
if (props.style) {
|
|
491
|
+
const ratio = `${width}/${height}`;
|
|
492
|
+
if (typeof props.style === "string") {
|
|
493
|
+
props.style = props.style.replace(/aspect-ratio: \d+\/\d+/, `aspect-ratio: ${ratio}`);
|
|
494
|
+
} else if (props.style.aspectRatio) {
|
|
495
|
+
props.style.aspectRatio = ratio;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
344
498
|
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
return instance;
|
|
499
|
+
});
|
|
500
|
+
writeFile(path, { module: true, parsed });
|
|
501
|
+
return parsed;
|
|
350
502
|
}
|
|
351
503
|
|
|
352
504
|
const resolve = createResolver(import.meta.url).resolve;
|
|
505
|
+
const meta = {
|
|
506
|
+
moduleName: "nuxt-content-assets",
|
|
507
|
+
moduleKey: "contentAssets",
|
|
508
|
+
compatibility: {
|
|
509
|
+
nuxt: "^3.0.0"
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
const defaults = {
|
|
513
|
+
imageSize: "style",
|
|
514
|
+
contentExtensions: "md csv ya?ml json",
|
|
515
|
+
debug: false
|
|
516
|
+
};
|
|
353
517
|
const module = defineNuxtModule({
|
|
354
|
-
meta
|
|
355
|
-
name: moduleName,
|
|
356
|
-
configKey: moduleKey,
|
|
357
|
-
compatibility: {
|
|
358
|
-
nuxt: "^3.0.0"
|
|
359
|
-
}
|
|
360
|
-
},
|
|
518
|
+
meta,
|
|
361
519
|
defaults,
|
|
362
520
|
async setup(options, nuxt) {
|
|
363
521
|
var _a, _b;
|
|
364
|
-
const pluginPath = resolve("./runtime/plugin");
|
|
365
522
|
const buildPath = nuxt.options.buildDir;
|
|
366
|
-
const
|
|
367
|
-
const publicPath = Path.join(
|
|
368
|
-
const
|
|
523
|
+
const assetsPath = Path.join(buildPath, "content-assets");
|
|
524
|
+
const publicPath = Path.join(assetsPath, "public");
|
|
525
|
+
const contentPath = Path.join(buildPath, "content-cache/parsed");
|
|
369
526
|
if (options.debug) {
|
|
370
527
|
log("Removing cache folders...");
|
|
371
528
|
}
|
|
372
529
|
removeFolder(Path.join(buildPath, "content-cache"));
|
|
373
|
-
removeFolder(
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
(
|
|
530
|
+
removeFolder(assetsPath);
|
|
531
|
+
const { contentExtensions } = options;
|
|
532
|
+
if (contentExtensions) {
|
|
533
|
+
(_a = nuxt.options).content || (_a.content = {});
|
|
534
|
+
if (nuxt.options.content) {
|
|
535
|
+
(_b = nuxt.options.content).ignores || (_b.ignores = []);
|
|
536
|
+
}
|
|
537
|
+
const ignores = makeIgnores(contentExtensions);
|
|
538
|
+
nuxt.options.content?.ignores.push(ignores);
|
|
377
539
|
}
|
|
378
|
-
const ignores = getIgnores(options.contentExtensions);
|
|
379
|
-
nuxt.options.content?.ignores.push(ignores);
|
|
380
540
|
const imageFlags = matchTokens(options.imageSize);
|
|
381
|
-
const sources = nuxt.options._layers.map((layer) => layer.config?.content?.sources).reduce((output, sources2) => {
|
|
541
|
+
const sources = Array.from(nuxt.options._layers).map((layer) => layer.config?.content?.sources).reduce((output, sources2) => {
|
|
382
542
|
if (sources2) {
|
|
383
543
|
Object.assign(output, sources2);
|
|
384
544
|
}
|
|
@@ -393,34 +553,33 @@ const module = defineNuxtModule({
|
|
|
393
553
|
};
|
|
394
554
|
}
|
|
395
555
|
}
|
|
396
|
-
|
|
397
|
-
const { srcRel, srcAttr } = getAssetPaths(publicPath, src);
|
|
398
|
-
const { width, height, ratio, query } = getAssetSizes(src, imageFlags);
|
|
399
|
-
assets[srcRel] = {
|
|
400
|
-
srcRel,
|
|
401
|
-
srcAttr,
|
|
402
|
-
width,
|
|
403
|
-
height,
|
|
404
|
-
ratio,
|
|
405
|
-
query
|
|
406
|
-
};
|
|
407
|
-
saveAssets();
|
|
408
|
-
return srcAttr;
|
|
409
|
-
}
|
|
410
|
-
function removeAsset(src) {
|
|
411
|
-
const { srcRel, srcAttr } = getAssetPaths(publicPath, src);
|
|
412
|
-
delete assets[srcRel];
|
|
413
|
-
saveAssets();
|
|
414
|
-
return srcAttr;
|
|
415
|
-
}
|
|
416
|
-
const saveAssets = debounce(() => {
|
|
417
|
-
writeFile(indexPath, assets);
|
|
418
|
-
}, 50);
|
|
419
|
-
const assets = {};
|
|
556
|
+
const assets = makeAssetsManager(publicPath);
|
|
420
557
|
function onAssetChange(event, absTrg) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
558
|
+
let src = "";
|
|
559
|
+
let width;
|
|
560
|
+
let height;
|
|
561
|
+
if (event === "update") {
|
|
562
|
+
const oldAsset = isImage(absTrg) && imageFlags.length ? assets.getAsset(absTrg) : null;
|
|
563
|
+
const newAsset = assets.setAsset(absTrg);
|
|
564
|
+
width = newAsset.width;
|
|
565
|
+
height = newAsset.height;
|
|
566
|
+
if (oldAsset) {
|
|
567
|
+
if (oldAsset.width !== newAsset.width || oldAsset.height !== newAsset.height) {
|
|
568
|
+
newAsset.content.forEach(async (id) => {
|
|
569
|
+
const path = Path.join(contentPath, toPath(id));
|
|
570
|
+
rewriteContent(path, newAsset);
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
src = newAsset.srcAttr;
|
|
575
|
+
} else {
|
|
576
|
+
const asset = assets.removeAsset(absTrg);
|
|
577
|
+
if (asset) {
|
|
578
|
+
src = asset.srcAttr;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (src && socket) {
|
|
582
|
+
socket.send({ event, src, width, height });
|
|
424
583
|
}
|
|
425
584
|
}
|
|
426
585
|
addPlugin(resolve("./runtime/sockets/plugin"));
|
|
@@ -435,22 +594,24 @@ const module = defineNuxtModule({
|
|
|
435
594
|
nuxt.hook("build:before", async function() {
|
|
436
595
|
for (const [key, manager] of Object.entries(managers)) {
|
|
437
596
|
const paths = await manager.init();
|
|
438
|
-
paths.forEach((path) =>
|
|
597
|
+
paths.forEach((path) => assets.setAsset(path));
|
|
439
598
|
if (options.debug) {
|
|
440
599
|
list(`Copied "${key}" assets`, paths.map((path) => Path.relative(publicPath, path)));
|
|
441
600
|
}
|
|
442
601
|
}
|
|
443
602
|
});
|
|
603
|
+
const pluginPath = resolve("./runtime/content/plugin");
|
|
444
604
|
const makeVar = (name, value) => `export const ${name} = ${JSON.stringify(value)};`;
|
|
445
605
|
const virtualConfig = [
|
|
446
|
-
makeVar("
|
|
606
|
+
makeVar("publicPath", publicPath),
|
|
607
|
+
makeVar("imageFlags", imageFlags),
|
|
447
608
|
makeVar("debug", options.debug)
|
|
448
609
|
].join("\n");
|
|
449
610
|
nuxt.hook("nitro:config", async (config) => {
|
|
450
611
|
config.plugins || (config.plugins = []);
|
|
451
612
|
config.plugins.push(pluginPath);
|
|
452
613
|
config.virtual || (config.virtual = {});
|
|
453
|
-
config.virtual[`#${moduleName}`] = () => {
|
|
614
|
+
config.virtual[`#${meta.moduleName}`] = () => {
|
|
454
615
|
return virtualConfig;
|
|
455
616
|
};
|
|
456
617
|
config.publicAssets || (config.publicAssets = []);
|