nuxt-content-assets 0.7.0 → 0.9.0-alpha
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 +45 -141
- package/dist/module.d.ts +0 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +275 -163
- 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/sockets/client.d.ts +2 -0
- package/dist/runtime/services/sockets/client.mjs +9 -0
- package/dist/runtime/services/sockets/composable.d.ts +4 -0
- package/dist/runtime/services/sockets/composable.mjs +77 -0
- package/dist/runtime/services/sockets/server.d.ts +23 -0
- package/dist/runtime/services/sockets/server.mjs +78 -0
- package/dist/runtime/services/sources.d.ts +22 -10
- package/dist/runtime/services/sources.mjs +85 -32
- 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/dist/runtime/watcher.d.ts +2 -0
- package/dist/runtime/watcher.mjs +18 -0
- package/package.json +8 -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 { 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 { WebSocketServer } from 'ws';
|
|
12
|
+
import { listen } from 'listhen';
|
|
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,30 +85,6 @@ function removeFolder(path) {
|
|
|
65
85
|
}
|
|
66
86
|
}
|
|
67
87
|
|
|
68
|
-
const replacers = {
|
|
69
|
-
key: (src) => Path__default.dirname(src).split("/").filter((e) => e).shift() || "",
|
|
70
|
-
path: (src) => Path__default.dirname(src),
|
|
71
|
-
folder: (src) => Path__default.dirname(src).replace(/[^/]+\//, ""),
|
|
72
|
-
file: (src) => Path__default.basename(src),
|
|
73
|
-
name: (src) => Path__default.basename(src, Path__default.extname(src)),
|
|
74
|
-
extname: (src) => Path__default.extname(src),
|
|
75
|
-
ext: (src) => Path__default.extname(src).substring(1),
|
|
76
|
-
hash: (src) => hash({ src })
|
|
77
|
-
};
|
|
78
|
-
function interpolatePattern(pattern, src, warn = false) {
|
|
79
|
-
return Path__default.join(pattern.replace(/\[\w+]/g, (match) => {
|
|
80
|
-
const name = match.substring(1, match.length - 1);
|
|
81
|
-
const fn = replacers[name];
|
|
82
|
-
if (fn) {
|
|
83
|
-
return fn(src);
|
|
84
|
-
}
|
|
85
|
-
if (warn) {
|
|
86
|
-
log(`Unknown output token ${match}`, true);
|
|
87
|
-
}
|
|
88
|
-
return match;
|
|
89
|
-
}));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
88
|
function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
93
89
|
let width = void 0;
|
|
94
90
|
let height = void 0;
|
|
@@ -111,45 +107,199 @@ function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
|
111
107
|
warn(`could not read image "${srcAbs}`);
|
|
112
108
|
}
|
|
113
109
|
}
|
|
114
|
-
const srcRel = Path.
|
|
115
|
-
const srcAttr =
|
|
110
|
+
const srcRel = Path.relative(srcDir, srcAbs);
|
|
111
|
+
const srcAttr = "/" + srcRel;
|
|
116
112
|
const id = srcRel.replaceAll("/", ":");
|
|
117
113
|
return { id, srcRel, srcAttr, width, height, ratio, query };
|
|
118
114
|
}
|
|
119
115
|
|
|
120
|
-
|
|
116
|
+
function makeStorage(source, key = "") {
|
|
121
117
|
const storage = createStorage();
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
+
}
|
|
146
179
|
}
|
|
180
|
+
return absTrg;
|
|
147
181
|
}
|
|
148
|
-
|
|
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
|
+
};
|
|
149
202
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
203
|
+
|
|
204
|
+
const replacers = {
|
|
205
|
+
key: (src) => Path__default.dirname(src).split("/").filter((e) => e).shift() || "",
|
|
206
|
+
path: (src) => Path__default.dirname(src),
|
|
207
|
+
folder: (src) => Path__default.dirname(src).replace(/[^/]+\//, ""),
|
|
208
|
+
file: (src) => Path__default.basename(src),
|
|
209
|
+
name: (src) => Path__default.basename(src, Path__default.extname(src)),
|
|
210
|
+
extname: (src) => Path__default.extname(src),
|
|
211
|
+
ext: (src) => Path__default.extname(src).substring(1),
|
|
212
|
+
hash: (src) => hash({ src })
|
|
213
|
+
};
|
|
214
|
+
function interpolatePattern(pattern, src, warn = false) {
|
|
215
|
+
return Path__default.join(pattern.replace(/\[\w+]/g, (match) => {
|
|
216
|
+
const name = match.substring(1, match.length - 1);
|
|
217
|
+
const fn = replacers[name];
|
|
218
|
+
if (fn) {
|
|
219
|
+
return fn(src);
|
|
220
|
+
}
|
|
221
|
+
if (warn) {
|
|
222
|
+
log(`Unknown output token ${match}`, true);
|
|
223
|
+
}
|
|
224
|
+
return match;
|
|
225
|
+
}));
|
|
226
|
+
}
|
|
227
|
+
|
|
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, channel = "*") => {
|
|
232
|
+
data = JSON.stringify({ channel, data });
|
|
233
|
+
for (const client of wss.clients) {
|
|
234
|
+
try {
|
|
235
|
+
client.send(data);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const handlers = [];
|
|
241
|
+
const onMessage = (channel, callback) => {
|
|
242
|
+
handlers.push({ channel, callback });
|
|
243
|
+
};
|
|
244
|
+
wss.on("connection", (client) => {
|
|
245
|
+
client.addEventListener("message", (event) => {
|
|
246
|
+
try {
|
|
247
|
+
const { channel, data } = JSON.parse(event.data || "{}");
|
|
248
|
+
handlers.filter((handler) => handler.channel === channel || handler.channel === "*").forEach((handler) => handler.callback(data));
|
|
249
|
+
} catch (err) {
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
wss,
|
|
255
|
+
serve,
|
|
256
|
+
broadcast,
|
|
257
|
+
onMessage,
|
|
258
|
+
close: () => {
|
|
259
|
+
wss.clients.forEach((client) => client.close());
|
|
260
|
+
return new Promise((resolve) => wss.close(resolve));
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
const ws = createWebSocket();
|
|
265
|
+
let initialized = false;
|
|
266
|
+
const defaults = {
|
|
267
|
+
port: {
|
|
268
|
+
port: 4001,
|
|
269
|
+
portRange: [4001, 4040]
|
|
270
|
+
},
|
|
271
|
+
hostname: "localhost",
|
|
272
|
+
showURL: false
|
|
273
|
+
};
|
|
274
|
+
function useSocketServer(nuxt, channel, onMessage) {
|
|
275
|
+
nuxt.hook("nitro:init", async (nitro) => {
|
|
276
|
+
if (!initialized) {
|
|
277
|
+
initialized = true;
|
|
278
|
+
const { server, url } = await listen(() => "Nuxt Sockets", defaults);
|
|
279
|
+
server.on("upgrade", ws.serve);
|
|
280
|
+
nitro.options.runtimeConfig.public.sockets = {
|
|
281
|
+
wsUrl: url.replace("http", "ws")
|
|
282
|
+
};
|
|
283
|
+
nitro.hooks.hook("close", async () => {
|
|
284
|
+
await ws.close();
|
|
285
|
+
await server.close();
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
const instance = {
|
|
290
|
+
send(data) {
|
|
291
|
+
ws.broadcast(data, channel);
|
|
292
|
+
return this;
|
|
293
|
+
},
|
|
294
|
+
onMessage(callback) {
|
|
295
|
+
ws.onMessage(channel, callback);
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
if (onMessage) {
|
|
300
|
+
instance.onMessage(onMessage);
|
|
301
|
+
}
|
|
302
|
+
return instance;
|
|
153
303
|
}
|
|
154
304
|
|
|
155
305
|
const resolve = createResolver(import.meta.url).resolve;
|
|
@@ -162,9 +312,7 @@ const module = defineNuxtModule({
|
|
|
162
312
|
}
|
|
163
313
|
},
|
|
164
314
|
defaults: {
|
|
165
|
-
output: `${defaults.assetsDir}/${defaults.assetsPattern}`,
|
|
166
|
-
extensions: "",
|
|
167
|
-
additionalExtensions: "",
|
|
315
|
+
output: `${defaults$1.assetsDir}/${defaults$1.assetsPattern}`,
|
|
168
316
|
imageSize: "",
|
|
169
317
|
debug: false
|
|
170
318
|
},
|
|
@@ -174,37 +322,22 @@ const module = defineNuxtModule({
|
|
|
174
322
|
const buildPath = nuxt.options.buildDir;
|
|
175
323
|
const cachePath = Path.join(buildPath, "content-assets");
|
|
176
324
|
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
|
-
};
|
|
325
|
+
const indexPath = Path.join(cachePath, "assets.json");
|
|
183
326
|
if (options.debug) {
|
|
184
327
|
log("Removing cache folders...");
|
|
185
328
|
}
|
|
186
329
|
removeFolder(Path.join(buildPath, "content-cache"));
|
|
187
330
|
removeFolder(cachePath);
|
|
188
|
-
removeFolder(tempPath);
|
|
189
331
|
(_a = nuxt.options).content || (_a.content = {});
|
|
190
332
|
if (nuxt.options.content) {
|
|
191
333
|
(_b = nuxt.options.content).ignores || (_b.ignores = []);
|
|
192
334
|
}
|
|
193
|
-
|
|
335
|
+
nuxt.options.content?.ignores.push("^((?!(md|json|yaml|csv)).)*$");
|
|
336
|
+
const output = options.output || defaults$1.assetsDir;
|
|
194
337
|
const matches = output.match(/([^[]+)(.*)?/);
|
|
195
|
-
const
|
|
196
|
-
const assetsPattern = (matches ? matches[2] : "") || defaults.assetsPattern;
|
|
338
|
+
const assetsPattern = (matches ? matches[2] : "") || defaults$1.assetsPattern;
|
|
197
339
|
interpolatePattern(assetsPattern, "", true);
|
|
198
340
|
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
341
|
const sources = nuxt.options._layers.map((layer) => layer.config?.content?.sources).reduce((output2, sources2) => {
|
|
209
342
|
if (sources2) {
|
|
210
343
|
Object.assign(output2, sources2);
|
|
@@ -220,92 +353,71 @@ const module = defineNuxtModule({
|
|
|
220
353
|
};
|
|
221
354
|
}
|
|
222
355
|
}
|
|
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
|
-
}
|
|
356
|
+
addPlugin(resolve("./runtime/watcher"));
|
|
357
|
+
const socket = nuxt.options.dev ? useSocketServer(nuxt, "content-assets") : null;
|
|
358
|
+
function removeAsset(src) {
|
|
359
|
+
const srcRel = Path.relative(publicPath, src);
|
|
360
|
+
delete assets[srcRel];
|
|
361
|
+
saveAssets();
|
|
362
|
+
return "/" + srcRel;
|
|
266
363
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
364
|
+
function updateAsset(src) {
|
|
365
|
+
const {
|
|
366
|
+
srcRel,
|
|
367
|
+
srcAttr,
|
|
368
|
+
width,
|
|
369
|
+
height,
|
|
370
|
+
ratio,
|
|
371
|
+
query
|
|
372
|
+
} = getAssetConfig(publicPath, src, assetsPattern, imageFlags);
|
|
373
|
+
assets[srcRel] = {
|
|
374
|
+
srcRel,
|
|
375
|
+
srcAttr,
|
|
376
|
+
width,
|
|
377
|
+
height,
|
|
378
|
+
ratio,
|
|
379
|
+
query
|
|
380
|
+
};
|
|
381
|
+
saveAssets();
|
|
382
|
+
return srcAttr;
|
|
383
|
+
}
|
|
384
|
+
function watchAsset(event, absTrg) {
|
|
385
|
+
const srcAttr = event === "update" ? updateAsset(absTrg) : removeAsset(absTrg);
|
|
386
|
+
if (socket) {
|
|
387
|
+
socket.send({ event: "update", src: srcAttr });
|
|
270
388
|
}
|
|
389
|
+
}
|
|
390
|
+
const saveAssets = debounce(() => {
|
|
391
|
+
writeFile(indexPath, assets);
|
|
392
|
+
}, 50);
|
|
393
|
+
const assets = {};
|
|
394
|
+
const managers = {};
|
|
395
|
+
for (const [key, source] of Object.entries(sources)) {
|
|
271
396
|
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
|
-
}
|
|
397
|
+
log(`Creating source "${key}"`);
|
|
283
398
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
399
|
+
managers[key] = makeSourceManager(key, source, publicPath, watchAsset);
|
|
400
|
+
}
|
|
401
|
+
nuxt.hook("build:before", async function() {
|
|
402
|
+
for (const [key, manager] of Object.entries(managers)) {
|
|
403
|
+
const paths = await manager.init();
|
|
404
|
+
paths.forEach((path) => updateAsset(path));
|
|
405
|
+
if (options.debug) {
|
|
406
|
+
list(`Copied "${key}" assets`, paths.map((path) => Path.relative(publicPath, path)));
|
|
290
407
|
}
|
|
291
408
|
}
|
|
292
409
|
});
|
|
293
|
-
const nitroAssets = Object.entries(assets).reduce((output2, [key, value]) => {
|
|
294
|
-
output2[key] = value.config;
|
|
295
|
-
return output2;
|
|
296
|
-
}, {});
|
|
297
410
|
const virtualConfig = [
|
|
298
|
-
`export const assets = ${JSON.stringify(
|
|
411
|
+
// `export const assets = ${JSON.stringify(assets, null, ' ')}`,
|
|
412
|
+
`export const cachePath = '${cachePath}'`
|
|
299
413
|
].join("\n");
|
|
300
|
-
nuxt.options.alias[`#${moduleName}`] = addTemplate({
|
|
301
|
-
filename: `${moduleName}.mjs`,
|
|
302
|
-
getContents: () => virtualConfig
|
|
303
|
-
}).dst;
|
|
304
414
|
nuxt.hook("nitro:config", async (config) => {
|
|
305
415
|
config.plugins || (config.plugins = []);
|
|
306
416
|
config.plugins.push(pluginPath);
|
|
307
417
|
config.virtual || (config.virtual = {});
|
|
308
|
-
config.virtual[`#${moduleName}`] =
|
|
418
|
+
config.virtual[`#${moduleName}`] = () => {
|
|
419
|
+
return virtualConfig;
|
|
420
|
+
};
|
|
309
421
|
config.publicAssets || (config.publicAssets = []);
|
|
310
422
|
config.publicAssets.push({
|
|
311
423
|
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
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
export function useSocketClient(channel, onMessage) {
|
|
3
|
+
const url = useRuntimeConfig().public.sockets?.wsUrl;
|
|
4
|
+
if (process.client && url) {
|
|
5
|
+
import("./composable").then(({ useSocket }) => {
|
|
6
|
+
useSocket(channel, onMessage);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
}
|