nuxt-content-assets 0.7.0 → 0.9.0-beta
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 +46 -142
- package/dist/module.d.ts +0 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +299 -161
- package/dist/runtime/options.d.ts +4 -4
- package/dist/runtime/options.mjs +4 -8
- package/dist/runtime/plugin.mjs +15 -3
- package/dist/runtime/services/assets.d.ts +1 -1
- package/dist/runtime/services/assets.mjs +2 -3
- package/dist/runtime/services/sources.d.ts +22 -10
- package/dist/runtime/services/sources.mjs +85 -32
- package/dist/runtime/sockets/composable.d.ts +2 -0
- package/dist/runtime/sockets/composable.mjs +12 -0
- package/dist/runtime/sockets/factory.d.ts +5 -0
- package/dist/runtime/sockets/factory.mjs +86 -0
- package/dist/runtime/sockets/plugin.d.ts +2 -0
- package/dist/runtime/sockets/plugin.mjs +22 -0
- package/dist/runtime/sockets/setup.d.ts +2 -0
- package/dist/runtime/sockets/setup.mjs +26 -0
- package/dist/runtime/utils/assert.d.ts +7 -3
- package/dist/runtime/utils/assert.mjs +7 -4
- package/dist/runtime/utils/fs.d.ts +3 -0
- package/dist/runtime/utils/fs.mjs +12 -0
- package/dist/runtime/utils/string.d.ts +3 -0
- package/dist/runtime/utils/string.mjs +9 -0
- package/package.json +7 -2
package/dist/module.mjs
CHANGED
|
@@ -1,33 +1,45 @@
|
|
|
1
1
|
import * as Fs from 'fs';
|
|
2
2
|
import * as Path from 'path';
|
|
3
3
|
import Path__default from 'path';
|
|
4
|
-
import { createResolver, defineNuxtModule,
|
|
4
|
+
import { useNuxt, createResolver, defineNuxtModule, addPlugin } from '@nuxt/kit';
|
|
5
|
+
import debounce from 'debounce';
|
|
5
6
|
import getImageSize from 'image-size';
|
|
6
|
-
import { hash } from 'ohash';
|
|
7
|
-
import glob from 'glob';
|
|
8
7
|
import { createStorage } from 'unstorage';
|
|
9
8
|
import githubDriver from 'unstorage/drivers/github';
|
|
9
|
+
import fsDriver from 'unstorage/drivers/fs';
|
|
10
|
+
import { hash } from 'ohash';
|
|
11
|
+
import { listen } from 'listhen';
|
|
12
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
10
13
|
|
|
11
14
|
function matchWords(value) {
|
|
12
15
|
return typeof value === "string" ? value.match(/\w+/g) || [] : [];
|
|
13
16
|
}
|
|
17
|
+
function toPath(key) {
|
|
18
|
+
return key.replaceAll(":", "/");
|
|
19
|
+
}
|
|
20
|
+
function deKey(path) {
|
|
21
|
+
return path.replace(/^[^:]+:/, "");
|
|
22
|
+
}
|
|
14
23
|
|
|
15
|
-
const defaults = {
|
|
24
|
+
const defaults$1 = {
|
|
16
25
|
assetsDir: "/assets/",
|
|
17
26
|
assetsPattern: "[path]/[file]"
|
|
18
27
|
};
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
...imageExtensions,
|
|
24
|
-
...mediaExtensions,
|
|
25
|
-
...fileExtensions
|
|
26
|
-
];
|
|
28
|
+
const extensions = {
|
|
29
|
+
image: matchWords("png jpg jpeg gif svg webp ico"),
|
|
30
|
+
media: matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
|
|
31
|
+
};
|
|
27
32
|
|
|
28
33
|
function isImage(path) {
|
|
29
34
|
const ext = Path__default.extname(path).substring(1);
|
|
30
|
-
return
|
|
35
|
+
return extensions.image.includes(ext);
|
|
36
|
+
}
|
|
37
|
+
function isArticle(path) {
|
|
38
|
+
return /\.mdx?$/.test(path);
|
|
39
|
+
}
|
|
40
|
+
function isAsset(path) {
|
|
41
|
+
const ext = Path__default.extname(path);
|
|
42
|
+
return !!ext && ext !== ".DS_Store" && !isArticle(path);
|
|
31
43
|
}
|
|
32
44
|
|
|
33
45
|
const moduleName = "nuxt-content-assets";
|
|
@@ -51,10 +63,18 @@ function writeFile(path, data) {
|
|
|
51
63
|
createFolder(Path.dirname(path));
|
|
52
64
|
Fs.writeFileSync(path, text, { encoding: "utf8" });
|
|
53
65
|
}
|
|
66
|
+
async function writeBlob(path, data) {
|
|
67
|
+
const buffer = Buffer.from(await data.arrayBuffer());
|
|
68
|
+
createFolder(Path.dirname(path));
|
|
69
|
+
Fs.writeFileSync(path, buffer);
|
|
70
|
+
}
|
|
54
71
|
function copyFile(src, trg) {
|
|
55
72
|
createFolder(Path.dirname(trg));
|
|
56
73
|
Fs.copyFileSync(src, trg);
|
|
57
74
|
}
|
|
75
|
+
function removeFile(src) {
|
|
76
|
+
Fs.rmSync(src);
|
|
77
|
+
}
|
|
58
78
|
function createFolder(path) {
|
|
59
79
|
Fs.mkdirSync(path, { recursive: true });
|
|
60
80
|
}
|
|
@@ -65,6 +85,122 @@ function removeFolder(path) {
|
|
|
65
85
|
}
|
|
66
86
|
}
|
|
67
87
|
|
|
88
|
+
function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
89
|
+
let width = void 0;
|
|
90
|
+
let height = void 0;
|
|
91
|
+
let ratio = void 0;
|
|
92
|
+
let query = void 0;
|
|
93
|
+
if (hints.length && isImage(srcAbs)) {
|
|
94
|
+
try {
|
|
95
|
+
const size = getImageSize(srcAbs);
|
|
96
|
+
if (hints.includes("style")) {
|
|
97
|
+
ratio = `${size.width}/${size.height}`;
|
|
98
|
+
}
|
|
99
|
+
if (hints.includes("attrs")) {
|
|
100
|
+
width = size.width;
|
|
101
|
+
height = size.height;
|
|
102
|
+
}
|
|
103
|
+
if (hints.includes("url")) {
|
|
104
|
+
query = `?width=${width}&height=${height}`;
|
|
105
|
+
}
|
|
106
|
+
} catch (err) {
|
|
107
|
+
warn(`could not read image "${srcAbs}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const srcRel = Path.relative(srcDir, srcAbs);
|
|
111
|
+
const srcAttr = "/" + srcRel;
|
|
112
|
+
const id = srcRel.replaceAll("/", ":");
|
|
113
|
+
return { id, srcRel, srcAttr, width, height, ratio, query };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function makeStorage(source, key = "") {
|
|
117
|
+
const storage = createStorage();
|
|
118
|
+
const options = typeof source === "string" ? { driver: "fs", base: source } : source;
|
|
119
|
+
switch (options.driver) {
|
|
120
|
+
case "fs":
|
|
121
|
+
storage.mount(key, fsDriver({
|
|
122
|
+
...options,
|
|
123
|
+
ignore: ["[^:]+?\\.md"]
|
|
124
|
+
}));
|
|
125
|
+
break;
|
|
126
|
+
case "github":
|
|
127
|
+
storage.mount(key, githubDriver({
|
|
128
|
+
branch: "main",
|
|
129
|
+
dir: "/",
|
|
130
|
+
...options
|
|
131
|
+
}));
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
return storage;
|
|
135
|
+
}
|
|
136
|
+
function makeSourceManager(key, source, publicPath, callback) {
|
|
137
|
+
async function onWatch(event, key2) {
|
|
138
|
+
if (isAsset(key2)) {
|
|
139
|
+
const path = event === "update" ? await copyItem(key2) : removeItem(key2);
|
|
140
|
+
if (callback) {
|
|
141
|
+
callback(event, path);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function getRelSrc(key2) {
|
|
146
|
+
return toPath(key2).replace(/\w+/, "").replace(source.prefix || "", "");
|
|
147
|
+
}
|
|
148
|
+
function getAbsSrc(key2) {
|
|
149
|
+
return Path.join(source.base, getRelSrc(key2));
|
|
150
|
+
}
|
|
151
|
+
function getRelTrg(key2) {
|
|
152
|
+
return Path.join(source.prefix || "", toPath(deKey(key2)));
|
|
153
|
+
}
|
|
154
|
+
function getAbsTrg(key2) {
|
|
155
|
+
return Path.join(publicPath, getRelTrg(key2));
|
|
156
|
+
}
|
|
157
|
+
function removeItem(key2) {
|
|
158
|
+
const absTrg = getAbsTrg(key2);
|
|
159
|
+
removeFile(absTrg);
|
|
160
|
+
return absTrg;
|
|
161
|
+
}
|
|
162
|
+
async function copyItem(key2) {
|
|
163
|
+
const absTrg = getAbsTrg(key2);
|
|
164
|
+
const driver = source.driver;
|
|
165
|
+
if (driver === "fs") {
|
|
166
|
+
const absSrc = getAbsSrc(key2);
|
|
167
|
+
copyFile(absSrc, absTrg);
|
|
168
|
+
} else if (driver === "github") {
|
|
169
|
+
try {
|
|
170
|
+
const data = await storage.getItem(key2);
|
|
171
|
+
if (data) {
|
|
172
|
+
data?.constructor.name === "Blob" ? await writeBlob(absTrg, data) : writeFile(absTrg, data);
|
|
173
|
+
} else {
|
|
174
|
+
warn(`No data for key "${key2}"`);
|
|
175
|
+
}
|
|
176
|
+
} catch (err) {
|
|
177
|
+
warn(err.message);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return absTrg;
|
|
181
|
+
}
|
|
182
|
+
async function getKeys() {
|
|
183
|
+
const keys = await storage.getKeys();
|
|
184
|
+
return keys.filter(isAsset);
|
|
185
|
+
}
|
|
186
|
+
async function init() {
|
|
187
|
+
const keys = await getKeys();
|
|
188
|
+
const paths = [];
|
|
189
|
+
for (const key2 of keys) {
|
|
190
|
+
const path = await copyItem(key2);
|
|
191
|
+
paths.push(path);
|
|
192
|
+
}
|
|
193
|
+
return paths;
|
|
194
|
+
}
|
|
195
|
+
const storage = makeStorage(source, key);
|
|
196
|
+
storage.watch(onWatch);
|
|
197
|
+
return {
|
|
198
|
+
storage,
|
|
199
|
+
init,
|
|
200
|
+
keys: getKeys
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
68
204
|
const replacers = {
|
|
69
205
|
key: (src) => Path__default.dirname(src).split("/").filter((e) => e).shift() || "",
|
|
70
206
|
path: (src) => Path__default.dirname(src),
|
|
@@ -89,67 +225,107 @@ function interpolatePattern(pattern, src, warn = false) {
|
|
|
89
225
|
}));
|
|
90
226
|
}
|
|
91
227
|
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (hints.includes("style")) {
|
|
101
|
-
ratio = `${size.width}/${size.height}`;
|
|
228
|
+
function createWebSocket() {
|
|
229
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
230
|
+
const serve = (req, socket = req.socket, head = "") => wss.handleUpgrade(req, socket, head, (client) => wss.emit("connection", client, req));
|
|
231
|
+
const broadcast = (data) => {
|
|
232
|
+
data = JSON.stringify(data);
|
|
233
|
+
for (const client of wss.clients) {
|
|
234
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
235
|
+
client.send(data);
|
|
102
236
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const handlers = [];
|
|
240
|
+
const addHandler = (callback) => {
|
|
241
|
+
handlers.push(callback);
|
|
242
|
+
};
|
|
243
|
+
wss.on("connection", (socket) => {
|
|
244
|
+
socket.addEventListener("message", (event) => {
|
|
245
|
+
let data;
|
|
246
|
+
try {
|
|
247
|
+
data = JSON.parse(event.data || "{}");
|
|
248
|
+
} catch (err) {
|
|
106
249
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
250
|
+
if (data) {
|
|
251
|
+
handlers.forEach((callback) => callback(data));
|
|
109
252
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
wss,
|
|
257
|
+
serve,
|
|
258
|
+
broadcast,
|
|
259
|
+
addHandler,
|
|
260
|
+
close: () => {
|
|
261
|
+
wss.clients.forEach((client) => client.close());
|
|
262
|
+
return new Promise((resolve) => wss.close(resolve));
|
|
112
263
|
}
|
|
113
|
-
}
|
|
114
|
-
const srcRel = Path.basename(srcDir) + srcAbs.substring(srcDir.length);
|
|
115
|
-
const srcAttr = interpolatePattern(pattern, srcRel);
|
|
116
|
-
const id = srcRel.replaceAll("/", ":");
|
|
117
|
-
return { id, srcRel, srcAttr, width, height, ratio, query };
|
|
264
|
+
};
|
|
118
265
|
}
|
|
119
266
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const prefix = source.prefix || "";
|
|
136
|
-
const paths = [];
|
|
137
|
-
for (const { id, data } of assetItems) {
|
|
138
|
-
if (data) {
|
|
139
|
-
const path = id.replaceAll(":", "/");
|
|
140
|
-
const absPath = Path.join(tempPath, path.replace(key, `${key}/${prefix}`));
|
|
141
|
-
const absFolder = Path.dirname(absPath);
|
|
142
|
-
const buffer = data.constructor.name === "Blob" ? Buffer.from(await data.arrayBuffer()) : typeof data === "object" ? JSON.stringify(data, null, " ") : String(data);
|
|
143
|
-
Fs.mkdirSync(absFolder, { recursive: true });
|
|
144
|
-
Fs.writeFileSync(absPath, buffer);
|
|
145
|
-
paths.push(absPath);
|
|
267
|
+
function isObject(data) {
|
|
268
|
+
return data && typeof data === "object" && !Array.isArray(data);
|
|
269
|
+
}
|
|
270
|
+
function makeChannelBroker(ws2) {
|
|
271
|
+
const handlers = [];
|
|
272
|
+
const broadcast = (channel, data) => {
|
|
273
|
+
ws2.broadcast({ channel, data });
|
|
274
|
+
};
|
|
275
|
+
const addHandler = (channel, callback) => {
|
|
276
|
+
handlers.push({ channel, callback });
|
|
277
|
+
};
|
|
278
|
+
ws2.addHandler(function(message) {
|
|
279
|
+
if (isObject(message)) {
|
|
280
|
+
const { channel } = message;
|
|
281
|
+
handlers.filter((handler) => handler.channel === channel || handler.channel === "*").forEach((handler) => handler.callback(message));
|
|
146
282
|
}
|
|
147
|
-
}
|
|
148
|
-
return
|
|
283
|
+
});
|
|
284
|
+
return {
|
|
285
|
+
broadcast,
|
|
286
|
+
addHandler
|
|
287
|
+
};
|
|
149
288
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
289
|
+
const ws = createWebSocket();
|
|
290
|
+
const broker = makeChannelBroker(ws);
|
|
291
|
+
const defaults = {
|
|
292
|
+
port: {
|
|
293
|
+
port: 4001,
|
|
294
|
+
portRange: [4001, 4040]
|
|
295
|
+
},
|
|
296
|
+
hostname: "localhost",
|
|
297
|
+
showURL: false
|
|
298
|
+
};
|
|
299
|
+
async function setupSocketServer(channel, handler) {
|
|
300
|
+
const nuxt = useNuxt();
|
|
301
|
+
nuxt.hook("nitro:init", async (nitro) => {
|
|
302
|
+
if (!nuxt._socketServer) {
|
|
303
|
+
const { server, url } = await listen(() => "Nuxt Sockets", defaults);
|
|
304
|
+
nuxt._socketServer = server;
|
|
305
|
+
server.on("upgrade", ws.serve);
|
|
306
|
+
nitro.options.runtimeConfig.public.sockets = {
|
|
307
|
+
wsUrl: url.replace("http", "ws")
|
|
308
|
+
};
|
|
309
|
+
nitro.hooks.hook("close", async () => {
|
|
310
|
+
await ws.close();
|
|
311
|
+
await server.close();
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
const instance = {
|
|
316
|
+
send(data) {
|
|
317
|
+
broker.broadcast(channel, data);
|
|
318
|
+
return this;
|
|
319
|
+
},
|
|
320
|
+
addHandler(callback) {
|
|
321
|
+
broker.addHandler(channel, callback);
|
|
322
|
+
return this;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
if (handler) {
|
|
326
|
+
instance.addHandler(handler);
|
|
327
|
+
}
|
|
328
|
+
return instance;
|
|
153
329
|
}
|
|
154
330
|
|
|
155
331
|
const resolve = createResolver(import.meta.url).resolve;
|
|
@@ -162,9 +338,7 @@ const module = defineNuxtModule({
|
|
|
162
338
|
}
|
|
163
339
|
},
|
|
164
340
|
defaults: {
|
|
165
|
-
output: `${defaults.assetsDir}/${defaults.assetsPattern}`,
|
|
166
|
-
extensions: "",
|
|
167
|
-
additionalExtensions: "",
|
|
341
|
+
output: `${defaults$1.assetsDir}/${defaults$1.assetsPattern}`,
|
|
168
342
|
imageSize: "",
|
|
169
343
|
debug: false
|
|
170
344
|
},
|
|
@@ -174,37 +348,22 @@ const module = defineNuxtModule({
|
|
|
174
348
|
const buildPath = nuxt.options.buildDir;
|
|
175
349
|
const cachePath = Path.join(buildPath, "content-assets");
|
|
176
350
|
const publicPath = Path.join(cachePath, "public");
|
|
177
|
-
const
|
|
178
|
-
const dump = (name, data) => {
|
|
179
|
-
const path = `${cachePath}/debug/${name}.json`;
|
|
180
|
-
log(`Dumping "${Path.relative("", path)}"`);
|
|
181
|
-
writeFile(path, data);
|
|
182
|
-
};
|
|
351
|
+
const indexPath = Path.join(cachePath, "assets.json");
|
|
183
352
|
if (options.debug) {
|
|
184
353
|
log("Removing cache folders...");
|
|
185
354
|
}
|
|
186
355
|
removeFolder(Path.join(buildPath, "content-cache"));
|
|
187
356
|
removeFolder(cachePath);
|
|
188
|
-
removeFolder(tempPath);
|
|
189
357
|
(_a = nuxt.options).content || (_a.content = {});
|
|
190
358
|
if (nuxt.options.content) {
|
|
191
359
|
(_b = nuxt.options.content).ignores || (_b.ignores = []);
|
|
192
360
|
}
|
|
193
|
-
|
|
361
|
+
nuxt.options.content?.ignores.push("^((?!(mdx?|json|ya?ml|csv)).)*$");
|
|
362
|
+
const output = options.output || defaults$1.assetsDir;
|
|
194
363
|
const matches = output.match(/([^[]+)(.*)?/);
|
|
195
|
-
const
|
|
196
|
-
const assetsPattern = (matches ? matches[2] : "") || defaults.assetsPattern;
|
|
364
|
+
const assetsPattern = (matches ? matches[2] : "") || defaults$1.assetsPattern;
|
|
197
365
|
interpolatePattern(assetsPattern, "", true);
|
|
198
366
|
const imageFlags = matchWords(options.imageSize);
|
|
199
|
-
if (options.extensions?.trim()) {
|
|
200
|
-
extensions.splice(0, extensions.length, ...matchWords(options.extensions));
|
|
201
|
-
} else if (options.additionalExtensions) {
|
|
202
|
-
extensions.push(...matchWords(options.additionalExtensions));
|
|
203
|
-
}
|
|
204
|
-
if (options.debug) {
|
|
205
|
-
log("Preparing sources...");
|
|
206
|
-
}
|
|
207
|
-
const assets = {};
|
|
208
367
|
const sources = nuxt.options._layers.map((layer) => layer.config?.content?.sources).reduce((output2, sources2) => {
|
|
209
368
|
if (sources2) {
|
|
210
369
|
Object.assign(output2, sources2);
|
|
@@ -220,92 +379,71 @@ const module = defineNuxtModule({
|
|
|
220
379
|
};
|
|
221
380
|
}
|
|
222
381
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
srcDir = source.base;
|
|
231
|
-
break;
|
|
232
|
-
case "github":
|
|
233
|
-
paths = await getGithubAssets(key, source, tempPath, extensions);
|
|
234
|
-
srcDir = Path.join(tempPath, key);
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
if (options.debug) {
|
|
238
|
-
log(`Prepared ${paths.length} paths for source "${key}"`);
|
|
239
|
-
}
|
|
240
|
-
if (paths.length) {
|
|
241
|
-
paths.forEach((src) => {
|
|
242
|
-
const {
|
|
243
|
-
id,
|
|
244
|
-
srcRel,
|
|
245
|
-
srcAttr,
|
|
246
|
-
width,
|
|
247
|
-
height,
|
|
248
|
-
ratio,
|
|
249
|
-
query
|
|
250
|
-
} = getAssetConfig(srcDir, src, assetsPattern, imageFlags);
|
|
251
|
-
nuxt.options.content.ignores.push(id);
|
|
252
|
-
const trg = Path.join(publicPath, assetsDir, srcAttr);
|
|
253
|
-
assets[srcRel] = {
|
|
254
|
-
src,
|
|
255
|
-
trg,
|
|
256
|
-
config: {
|
|
257
|
-
srcAttr: Path.join(assetsDir, srcAttr),
|
|
258
|
-
width,
|
|
259
|
-
height,
|
|
260
|
-
ratio,
|
|
261
|
-
query
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
});
|
|
265
|
-
}
|
|
382
|
+
addPlugin(resolve("./runtime/sockets/plugin"));
|
|
383
|
+
const socket = nuxt.options.dev ? await setupSocketServer("content-assets") : null;
|
|
384
|
+
function removeAsset(src) {
|
|
385
|
+
const srcRel = Path.relative(publicPath, src);
|
|
386
|
+
delete assets[srcRel];
|
|
387
|
+
saveAssets();
|
|
388
|
+
return "/" + srcRel;
|
|
266
389
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
390
|
+
function updateAsset(src) {
|
|
391
|
+
const {
|
|
392
|
+
srcRel,
|
|
393
|
+
srcAttr,
|
|
394
|
+
width,
|
|
395
|
+
height,
|
|
396
|
+
ratio,
|
|
397
|
+
query
|
|
398
|
+
} = getAssetConfig(publicPath, src, assetsPattern, 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 watchAsset(event, absTrg) {
|
|
411
|
+
const src = event === "update" ? updateAsset(absTrg) : removeAsset(absTrg);
|
|
412
|
+
if (socket) {
|
|
413
|
+
socket.send({ event, src });
|
|
270
414
|
}
|
|
415
|
+
}
|
|
416
|
+
const saveAssets = debounce(() => {
|
|
417
|
+
writeFile(indexPath, assets);
|
|
418
|
+
}, 50);
|
|
419
|
+
const assets = {};
|
|
420
|
+
const managers = {};
|
|
421
|
+
for (const [key, source] of Object.entries(sources)) {
|
|
271
422
|
if (options.debug) {
|
|
272
|
-
log(`
|
|
273
|
-
}
|
|
274
|
-
const copied = [];
|
|
275
|
-
const failed = [];
|
|
276
|
-
for (const [key, { src, trg }] of Object.entries(assets)) {
|
|
277
|
-
if (Fs.existsSync(src)) {
|
|
278
|
-
copyFile(src, trg);
|
|
279
|
-
copied.push(key);
|
|
280
|
-
} else {
|
|
281
|
-
failed.push(key);
|
|
282
|
-
}
|
|
423
|
+
log(`Creating source "${key}"`);
|
|
283
424
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
425
|
+
managers[key] = makeSourceManager(key, source, publicPath, watchAsset);
|
|
426
|
+
}
|
|
427
|
+
nuxt.hook("build:before", async function() {
|
|
428
|
+
for (const [key, manager] of Object.entries(managers)) {
|
|
429
|
+
const paths = await manager.init();
|
|
430
|
+
paths.forEach((path) => updateAsset(path));
|
|
431
|
+
if (options.debug) {
|
|
432
|
+
list(`Copied "${key}" assets`, paths.map((path) => Path.relative(publicPath, path)));
|
|
290
433
|
}
|
|
291
434
|
}
|
|
292
435
|
});
|
|
293
|
-
const nitroAssets = Object.entries(assets).reduce((output2, [key, value]) => {
|
|
294
|
-
output2[key] = value.config;
|
|
295
|
-
return output2;
|
|
296
|
-
}, {});
|
|
297
436
|
const virtualConfig = [
|
|
298
|
-
`export const assets = ${JSON.stringify(
|
|
437
|
+
// `export const assets = ${JSON.stringify(assets, null, ' ')}`,
|
|
438
|
+
`export const cachePath = '${cachePath}'`
|
|
299
439
|
].join("\n");
|
|
300
|
-
nuxt.options.alias[`#${moduleName}`] = addTemplate({
|
|
301
|
-
filename: `${moduleName}.mjs`,
|
|
302
|
-
getContents: () => virtualConfig
|
|
303
|
-
}).dst;
|
|
304
440
|
nuxt.hook("nitro:config", async (config) => {
|
|
305
441
|
config.plugins || (config.plugins = []);
|
|
306
442
|
config.plugins.push(pluginPath);
|
|
307
443
|
config.virtual || (config.virtual = {});
|
|
308
|
-
config.virtual[`#${moduleName}`] =
|
|
444
|
+
config.virtual[`#${moduleName}`] = () => {
|
|
445
|
+
return virtualConfig;
|
|
446
|
+
};
|
|
309
447
|
config.publicAssets || (config.publicAssets = []);
|
|
310
448
|
config.publicAssets.push({
|
|
311
449
|
dir: publicPath
|
|
@@ -2,8 +2,8 @@ export declare const defaults: {
|
|
|
2
2
|
assetsDir: string;
|
|
3
3
|
assetsPattern: string;
|
|
4
4
|
};
|
|
5
|
-
export declare const imageExtensions: string[];
|
|
6
|
-
export declare const mediaExtensions: string[];
|
|
7
|
-
export declare const fileExtensions: string[];
|
|
8
|
-
export declare const extensions: string[];
|
|
9
5
|
export declare const tags: string[];
|
|
6
|
+
export declare const extensions: {
|
|
7
|
+
image: string[];
|
|
8
|
+
media: string[];
|
|
9
|
+
};
|
package/dist/runtime/options.mjs
CHANGED
|
@@ -3,12 +3,8 @@ export const defaults = {
|
|
|
3
3
|
assetsDir: "/assets/",
|
|
4
4
|
assetsPattern: "[path]/[file]"
|
|
5
5
|
};
|
|
6
|
-
export const imageExtensions = matchWords("png jpg jpeg gif svg webp ico");
|
|
7
|
-
export const mediaExtensions = matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd");
|
|
8
|
-
export const fileExtensions = matchWords("pdf doc docx xls xlsx ppt pptx odp key");
|
|
9
|
-
export const extensions = [
|
|
10
|
-
...imageExtensions,
|
|
11
|
-
...mediaExtensions,
|
|
12
|
-
...fileExtensions
|
|
13
|
-
];
|
|
14
6
|
export const tags = ["img", "video", "audio", "source", "embed", "iframe", "a"];
|
|
7
|
+
export const extensions = {
|
|
8
|
+
image: matchWords("png jpg jpeg gif svg webp ico"),
|
|
9
|
+
media: matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
|
|
10
|
+
};
|
package/dist/runtime/plugin.mjs
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import Path from "path";
|
|
2
2
|
import { visit } from "unist-util-visit";
|
|
3
|
-
import { isValidAsset, walk } from "./utils/index.mjs";
|
|
3
|
+
import { deKey, isValidAsset, toPath, walk } from "./utils/index.mjs";
|
|
4
4
|
import { tags } from "./options.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { cachePath } from "#nuxt-content-assets";
|
|
6
|
+
import { makeStorage } from "./services/index.mjs";
|
|
7
|
+
async function updateAssets() {
|
|
8
|
+
assets = await storage.getItem("assets.json");
|
|
9
|
+
}
|
|
10
|
+
const storage = makeStorage(cachePath);
|
|
11
|
+
storage.watch(async (event, key) => {
|
|
12
|
+
if (event === "update" && key === "assets.json") {
|
|
13
|
+
await updateAssets();
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
let assets = {};
|
|
17
|
+
void updateAssets();
|
|
6
18
|
function getAsset(srcDoc, relAsset) {
|
|
7
19
|
const srcAsset = Path.join(Path.dirname(srcDoc), relAsset);
|
|
8
20
|
return assets[srcAsset] || {};
|
|
@@ -10,7 +22,7 @@ function getAsset(srcDoc, relAsset) {
|
|
|
10
22
|
const plugin = async (nitro) => {
|
|
11
23
|
nitro.hooks.hook("content:file:afterParse", async (file) => {
|
|
12
24
|
if (file._id.endsWith(".md")) {
|
|
13
|
-
const srcDoc = file._id
|
|
25
|
+
const srcDoc = toPath(deKey(file._id));
|
|
14
26
|
const filter = (value, key) => !(String(key).startsWith("_") || key === "body");
|
|
15
27
|
walk(file, (value, parent, key) => {
|
|
16
28
|
if (isValidAsset(value)) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as Path from "path";
|
|
2
2
|
import getImageSize from "image-size";
|
|
3
3
|
import { isImage, warn } from "../utils/index.mjs";
|
|
4
|
-
import { interpolatePattern } from "./paths.mjs";
|
|
5
4
|
export function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
6
5
|
let width = void 0;
|
|
7
6
|
let height = void 0;
|
|
@@ -24,8 +23,8 @@ export function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
|
24
23
|
warn(`could not read image "${srcAbs}`);
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
|
-
const srcRel = Path.
|
|
28
|
-
const srcAttr =
|
|
26
|
+
const srcRel = Path.relative(srcDir, srcAbs);
|
|
27
|
+
const srcAttr = "/" + srcRel;
|
|
29
28
|
const id = srcRel.replaceAll("/", ":");
|
|
30
29
|
return { id, srcRel, srcAttr, width, height, ratio, query };
|
|
31
30
|
}
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { WatchEvent, Storage } from 'unstorage';
|
|
2
|
+
import { MountOptions } from '@nuxt/content';
|
|
3
|
+
/**
|
|
4
|
+
* Make a Storage instance
|
|
5
|
+
*/
|
|
6
|
+
export declare function makeStorage(source: MountOptions | string, key?: string): Storage;
|
|
7
|
+
export interface SourceManager {
|
|
8
|
+
storage: Storage;
|
|
9
|
+
init: () => Promise<string[]>;
|
|
10
|
+
keys: () => Promise<string[]>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Make a SourceManager instance
|
|
14
|
+
*
|
|
15
|
+
* Each Source Manager is responsible for mirroring source files to the public folder
|
|
16
|
+
*
|
|
17
|
+
* @param key
|
|
18
|
+
* @param source
|
|
19
|
+
* @param publicPath
|
|
20
|
+
* @param callback
|
|
21
|
+
*/
|
|
22
|
+
export declare function makeSourceManager(key: string, source: MountOptions, publicPath: string, callback?: (event: WatchEvent, path: string) => void): SourceManager;
|