nuxt-content-assets 0.9.0-beta → 0.10.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 +63 -48
- package/dist/module.d.ts +2 -2
- package/dist/module.json +2 -2
- package/dist/module.mjs +67 -84
- package/dist/runtime/config.d.ts +1 -1
- package/dist/runtime/config.mjs +1 -1
- package/dist/runtime/options.d.ts +4 -3
- package/dist/runtime/options.mjs +14 -6
- package/dist/runtime/plugin.mjs +8 -11
- package/dist/runtime/services/assets.d.ts +17 -3
- package/dist/runtime/services/assets.mjs +17 -5
- package/dist/runtime/sockets/factory.mjs +4 -6
- package/dist/runtime/sockets/plugin.mjs +3 -4
- package/dist/runtime/utils/string.d.ts +4 -2
- package/dist/runtime/utils/string.mjs +5 -2
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,10 +40,10 @@ I loved being in the mountains.
|
|
|
40
40
|
|
|
41
41
|
Almost as much as being in the sea!
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
:video{src="media/seaside.mp4"}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
At build time the module [collates and serves](#how-it-works) assets and content together.
|
|
47
47
|
|
|
48
48
|
## Demo
|
|
49
49
|
|
|
@@ -82,8 +82,6 @@ export default defineNuxtConfig({
|
|
|
82
82
|
|
|
83
83
|
Run the dev server or build and local assets should now be served alongside markdown content.
|
|
84
84
|
|
|
85
|
-
See the [How it works](#how-it-works) section for more information.
|
|
86
|
-
|
|
87
85
|
## Usage
|
|
88
86
|
|
|
89
87
|
### Overview
|
|
@@ -91,15 +89,24 @@ See the [How it works](#how-it-works) section for more information.
|
|
|
91
89
|
Use relative paths anywhere within your documents:
|
|
92
90
|
|
|
93
91
|
```mdx
|
|
92
|
+
Images
|
|
94
93
|

|
|
95
|
-
|
|
94
|
+
|
|
95
|
+
Links
|
|
96
|
+
[link](docs/article.txt)
|
|
97
|
+
|
|
98
|
+
Elements / components
|
|
99
|
+
:video{src="media/video.mp4"}
|
|
100
|
+
|
|
101
|
+
HTML
|
|
102
|
+
<iframe src="media/example.html" />
|
|
96
103
|
```
|
|
97
104
|
|
|
98
105
|
Relative paths can be defined in frontmatter – as long as they are the only value:
|
|
99
106
|
|
|
100
107
|
```mdx
|
|
101
108
|
---
|
|
102
|
-
title: Portfolio
|
|
109
|
+
title: Portfolio
|
|
103
110
|
images:
|
|
104
111
|
- assets/image-1.jpg
|
|
105
112
|
- assets/image-2.jpg
|
|
@@ -110,27 +117,32 @@ images:
|
|
|
110
117
|
These values can then be passed to components:
|
|
111
118
|
|
|
112
119
|
```markdown
|
|
113
|
-
|
|
114
|
-
::
|
|
120
|
+
:image-gallery{:data="images"}
|
|
115
121
|
```
|
|
116
122
|
|
|
117
|
-
See the Demo for [markup](demo/content/
|
|
123
|
+
See the Demo for [markup](demo/content/advanced/gallery.md) and [component](demo/components/content/ContentGallery.vue) examples.
|
|
118
124
|
|
|
119
125
|
### Live reload
|
|
120
126
|
|
|
121
|
-
|
|
127
|
+
In development, the module watches for asset additions, moves and deletes, and will update the browser live.
|
|
122
128
|
|
|
123
|
-
|
|
129
|
+
If you delete an asset, it will be greyed out in the browser until you replace the file or modify the path to it.
|
|
130
|
+
|
|
131
|
+
If you edit an image, video, embed or iframe source, the content will update immediately, which is useful if you're looking to get that design just right!
|
|
124
132
|
|
|
125
133
|
### Image sizing
|
|
126
134
|
|
|
127
|
-
|
|
135
|
+
You can [configure](#image-size) the module to add image size attributes to generated `<img>` tags:
|
|
128
136
|
|
|
129
137
|
```html
|
|
130
|
-
<img src="/image.jpg
|
|
138
|
+
<img src="/image.jpg"
|
|
139
|
+
style="aspect-ratio:640/480"
|
|
140
|
+
width="640"
|
|
141
|
+
height="480"
|
|
142
|
+
>
|
|
131
143
|
```
|
|
132
144
|
|
|
133
|
-
If you use [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can hook into these values via the `$attrs` property:
|
|
145
|
+
If you use [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can [hook into these values](demo/components/temp/ProseImg.vue) via the `$attrs` property:
|
|
134
146
|
|
|
135
147
|
```vue
|
|
136
148
|
<template>
|
|
@@ -146,51 +158,32 @@ export default {
|
|
|
146
158
|
</script>
|
|
147
159
|
```
|
|
148
160
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
## How it works
|
|
152
|
-
|
|
153
|
-
Nuxt Content Assets works by serving a _copy_ of your assets using [Nitro](https://nitro.unjs.io/guide/assets#custom-server-assets).
|
|
154
|
-
|
|
155
|
-
When Nuxt builds, the following happens:
|
|
156
|
-
|
|
157
|
-
- content sources are scanned for valid assets
|
|
158
|
-
- found assets are copied to a temporary build folder
|
|
159
|
-
- any relative asset paths are rewritten as absolute
|
|
160
|
-
- metadata such as image size is written to a lookup file
|
|
161
|
-
- finally, Nitro serves the folder for public access
|
|
162
|
-
|
|
163
|
-
Note that in the rewriting phase, only specific tags and attributes are targeted :
|
|
161
|
+
If you pass [frontmatter](demo/content/advanced/gallery.md) to [custom components](demo/components/content/ContentImage.vue) set the `'url'` configuration option to encode size in the URL:
|
|
164
162
|
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
<img src="...">
|
|
168
|
-
<video src="...">
|
|
169
|
-
<audio src="...">
|
|
170
|
-
<source src="...">
|
|
171
|
-
<embed src="...">
|
|
172
|
-
<iframe src="...">
|
|
163
|
+
```
|
|
164
|
+
:image-gallery={:data="images"}
|
|
173
165
|
```
|
|
174
166
|
|
|
175
167
|
## Configuration
|
|
176
168
|
|
|
177
|
-
|
|
169
|
+
The module can be configured in your Nuxt configuration file:
|
|
178
170
|
|
|
179
171
|
```ts
|
|
180
172
|
// nuxt.config.ts
|
|
181
173
|
export default defineNuxtConfig({
|
|
182
|
-
|
|
183
|
-
//
|
|
174
|
+
contentAssets: {
|
|
175
|
+
// inject image sizes into the rendered html
|
|
184
176
|
imageSize: 'style',
|
|
185
177
|
|
|
186
|
-
//
|
|
178
|
+
// treat these extensions as content
|
|
179
|
+
contentExtensions: 'mdx? csv ya?ml json',
|
|
180
|
+
|
|
181
|
+
// output debug messages
|
|
187
182
|
debug: true,
|
|
188
183
|
}
|
|
189
184
|
})
|
|
190
185
|
```
|
|
191
186
|
|
|
192
|
-
Note that from version `0.9.0-alpha` the `output` location is no longer configurable; images are copied relative to their original locations.
|
|
193
|
-
|
|
194
187
|
### Image size
|
|
195
188
|
|
|
196
189
|
You can add one or more image size hints to the generated images:
|
|
@@ -203,11 +196,11 @@ You can add one or more image size hints to the generated images:
|
|
|
203
196
|
|
|
204
197
|
Pick from the following switches:
|
|
205
198
|
|
|
206
|
-
| Switch | What it does
|
|
207
|
-
|
|
208
|
-
| `style` | Adds `style="aspect-ratio:..."` to any `<img>` tag
|
|
209
|
-
| `attrs` | Adds `width` and `height` attributes to any `<img>` tag
|
|
210
|
-
| `url` | Adds
|
|
199
|
+
| Switch | What it does |
|
|
200
|
+
| ------- | ------------------------------------------------------------ |
|
|
201
|
+
| `style` | Adds `style="aspect-ratio:..."` to any `<img>` tag |
|
|
202
|
+
| `attrs` | Adds `width` and `height` attributes to any `<img>` tag |
|
|
203
|
+
| `url` | Adds a `?width=...&height=...` query string to image paths in frontmatter |
|
|
211
204
|
|
|
212
205
|
Note: if you add `attrs` only, include the following CSS in your app:
|
|
213
206
|
|
|
@@ -218,6 +211,18 @@ img {
|
|
|
218
211
|
}
|
|
219
212
|
```
|
|
220
213
|
|
|
214
|
+
### Content extensions
|
|
215
|
+
|
|
216
|
+
This setting tells Nuxt Content to ignore anything that is **not** one of these file extensions:
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
mdx? csv ya?ml json
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
This way, you can use any **other** file type as an asset, without needing to explicitly configure extensions.
|
|
223
|
+
|
|
224
|
+
Generally, you shouldn't need to touch this setting.
|
|
225
|
+
|
|
221
226
|
### Debug
|
|
222
227
|
|
|
223
228
|
If you want to see what the module does as it runs, set `debug` to true:
|
|
@@ -228,6 +233,16 @@ If you want to see what the module does as it runs, set `debug` to true:
|
|
|
228
233
|
}
|
|
229
234
|
```
|
|
230
235
|
|
|
236
|
+
## How it works
|
|
237
|
+
|
|
238
|
+
When Nuxt builds, the module scans all content sources for assets, copies them to an accessible public assets folder, and indexes path and image metadata.
|
|
239
|
+
|
|
240
|
+
After Nuxt Content has run the parsed content is traversed, and both element attributes and frontmatter properties are checked to see if they resolve to the indexed asset paths.
|
|
241
|
+
|
|
242
|
+
If they do, then the attribute or property is rewritten with the absolute path. If the asset is an image, then the element or path is optionally updated with size attributes or size query string.
|
|
243
|
+
|
|
244
|
+
Finally, Nitro serves the site, and any requests made to the transformed asset paths should be picked up and the *copied* asset served by the browser.
|
|
245
|
+
|
|
231
246
|
## Development
|
|
232
247
|
|
|
233
248
|
Should you wish to develop the project, the scripts are:
|
package/dist/module.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
2
|
|
|
3
3
|
interface ModuleOptions {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
imageSize?: string | string[];
|
|
5
|
+
contentExtensions: string | string[];
|
|
6
6
|
debug?: boolean;
|
|
7
7
|
}
|
|
8
8
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -7,12 +7,15 @@ import getImageSize from 'image-size';
|
|
|
7
7
|
import { createStorage } from 'unstorage';
|
|
8
8
|
import githubDriver from 'unstorage/drivers/github';
|
|
9
9
|
import fsDriver from 'unstorage/drivers/fs';
|
|
10
|
-
import
|
|
10
|
+
import 'ohash';
|
|
11
11
|
import { listen } from 'listhen';
|
|
12
12
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
|
|
14
|
+
function matchTokens(value) {
|
|
15
|
+
const tokens = typeof value === "string" ? value.match(/[^\s,|]+/g) || [] : Array.isArray(value) ? value.filter((value2) => typeof value2 === "string").reduce((output, input) => {
|
|
16
|
+
return [...output, ...matchTokens(input)];
|
|
17
|
+
}, []) : [];
|
|
18
|
+
return Array.from(new Set(tokens));
|
|
16
19
|
}
|
|
17
20
|
function toPath(key) {
|
|
18
21
|
return key.replaceAll(":", "/");
|
|
@@ -21,14 +24,23 @@ function deKey(path) {
|
|
|
21
24
|
return path.replace(/^[^:]+:/, "");
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
const defaults
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
const defaults = {
|
|
28
|
+
// inject image size into the rendered html
|
|
29
|
+
imageSize: "attrs",
|
|
30
|
+
// treat these extensions as content
|
|
31
|
+
contentExtensions: "mdx? csv ya?ml json",
|
|
32
|
+
// output debug messages
|
|
33
|
+
debug: false
|
|
27
34
|
};
|
|
28
35
|
const extensions = {
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
// used to get image size
|
|
37
|
+
image: matchTokens("png jpg jpeg gif svg webp ico"),
|
|
38
|
+
// unused for now
|
|
39
|
+
media: matchTokens("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
|
|
31
40
|
};
|
|
41
|
+
function getIgnores(extensions2) {
|
|
42
|
+
return `^((?!(${matchTokens(extensions2).join("|")})).)*$`;
|
|
43
|
+
}
|
|
32
44
|
|
|
33
45
|
function isImage(path) {
|
|
34
46
|
const ext = Path__default.extname(path).substring(1);
|
|
@@ -43,7 +55,7 @@ function isAsset(path) {
|
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
const moduleName = "nuxt-content-assets";
|
|
46
|
-
const moduleKey = "
|
|
58
|
+
const moduleKey = "contentAssets";
|
|
47
59
|
|
|
48
60
|
function log(...data) {
|
|
49
61
|
console.info(`[${moduleKey}]`, ...data);
|
|
@@ -85,7 +97,17 @@ function removeFolder(path) {
|
|
|
85
97
|
}
|
|
86
98
|
}
|
|
87
99
|
|
|
88
|
-
function
|
|
100
|
+
function getAssetPaths(srcDir, srcAbs) {
|
|
101
|
+
const srcRel = Path.relative(srcDir, srcAbs);
|
|
102
|
+
const srcAttr = "/" + srcRel;
|
|
103
|
+
const id = srcRel.replaceAll("/", ":");
|
|
104
|
+
return {
|
|
105
|
+
id,
|
|
106
|
+
srcRel,
|
|
107
|
+
srcAttr
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function getAssetSizes(srcAbs, hints) {
|
|
89
111
|
let width = void 0;
|
|
90
112
|
let height = void 0;
|
|
91
113
|
let ratio = void 0;
|
|
@@ -107,10 +129,12 @@ function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
|
107
129
|
warn(`could not read image "${srcAbs}`);
|
|
108
130
|
}
|
|
109
131
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
132
|
+
return {
|
|
133
|
+
width,
|
|
134
|
+
height,
|
|
135
|
+
ratio,
|
|
136
|
+
query
|
|
137
|
+
};
|
|
114
138
|
}
|
|
115
139
|
|
|
116
140
|
function makeStorage(source, key = "") {
|
|
@@ -201,30 +225,6 @@ function makeSourceManager(key, source, publicPath, callback) {
|
|
|
201
225
|
};
|
|
202
226
|
}
|
|
203
227
|
|
|
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
228
|
function createWebSocket() {
|
|
229
229
|
const wss = new WebSocketServer({ noServer: true });
|
|
230
230
|
const serve = (req, socket = req.socket, head = "") => wss.handleUpgrade(req, socket, head, (client) => wss.emit("connection", client, req));
|
|
@@ -288,19 +288,16 @@ function makeChannelBroker(ws2) {
|
|
|
288
288
|
}
|
|
289
289
|
const ws = createWebSocket();
|
|
290
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
291
|
async function setupSocketServer(channel, handler) {
|
|
300
292
|
const nuxt = useNuxt();
|
|
301
293
|
nuxt.hook("nitro:init", async (nitro) => {
|
|
302
294
|
if (!nuxt._socketServer) {
|
|
303
|
-
const
|
|
295
|
+
const defaults = nuxt.options.runtimeConfig.content.watch.ws;
|
|
296
|
+
const { server, url } = await listen(() => "Nuxt Content Assets", {
|
|
297
|
+
port: defaults.port.port + 1,
|
|
298
|
+
hostname: defaults.hostname,
|
|
299
|
+
showURL: false
|
|
300
|
+
});
|
|
304
301
|
nuxt._socketServer = server;
|
|
305
302
|
server.on("upgrade", ws.serve);
|
|
306
303
|
nitro.options.runtimeConfig.public.sockets = {
|
|
@@ -337,11 +334,7 @@ const module = defineNuxtModule({
|
|
|
337
334
|
nuxt: "^3.0.0"
|
|
338
335
|
}
|
|
339
336
|
},
|
|
340
|
-
defaults
|
|
341
|
-
output: `${defaults$1.assetsDir}/${defaults$1.assetsPattern}`,
|
|
342
|
-
imageSize: "",
|
|
343
|
-
debug: false
|
|
344
|
-
},
|
|
337
|
+
defaults,
|
|
345
338
|
async setup(options, nuxt) {
|
|
346
339
|
var _a, _b;
|
|
347
340
|
const pluginPath = resolve("./runtime/plugin");
|
|
@@ -358,17 +351,14 @@ const module = defineNuxtModule({
|
|
|
358
351
|
if (nuxt.options.content) {
|
|
359
352
|
(_b = nuxt.options.content).ignores || (_b.ignores = []);
|
|
360
353
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
interpolatePattern(assetsPattern, "", true);
|
|
366
|
-
const imageFlags = matchWords(options.imageSize);
|
|
367
|
-
const sources = nuxt.options._layers.map((layer) => layer.config?.content?.sources).reduce((output2, sources2) => {
|
|
354
|
+
const ignores = getIgnores(options.contentExtensions);
|
|
355
|
+
nuxt.options.content?.ignores.push(ignores);
|
|
356
|
+
const imageFlags = matchTokens(options.imageSize);
|
|
357
|
+
const sources = nuxt.options._layers.map((layer) => layer.config?.content?.sources).reduce((output, sources2) => {
|
|
368
358
|
if (sources2) {
|
|
369
|
-
Object.assign(
|
|
359
|
+
Object.assign(output, sources2);
|
|
370
360
|
}
|
|
371
|
-
return
|
|
361
|
+
return output;
|
|
372
362
|
}, {});
|
|
373
363
|
if (Object.keys(sources).length === 0 || !sources.content) {
|
|
374
364
|
const content = nuxt.options.srcDir + "/content";
|
|
@@ -379,23 +369,9 @@ const module = defineNuxtModule({
|
|
|
379
369
|
};
|
|
380
370
|
}
|
|
381
371
|
}
|
|
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;
|
|
389
|
-
}
|
|
390
372
|
function updateAsset(src) {
|
|
391
|
-
const {
|
|
392
|
-
|
|
393
|
-
srcAttr,
|
|
394
|
-
width,
|
|
395
|
-
height,
|
|
396
|
-
ratio,
|
|
397
|
-
query
|
|
398
|
-
} = getAssetConfig(publicPath, src, assetsPattern, imageFlags);
|
|
373
|
+
const { srcRel, srcAttr } = getAssetPaths(publicPath, src);
|
|
374
|
+
const { width, height, ratio, query } = getAssetSizes(src, imageFlags);
|
|
399
375
|
assets[srcRel] = {
|
|
400
376
|
srcRel,
|
|
401
377
|
srcAttr,
|
|
@@ -407,22 +383,30 @@ const module = defineNuxtModule({
|
|
|
407
383
|
saveAssets();
|
|
408
384
|
return srcAttr;
|
|
409
385
|
}
|
|
410
|
-
function
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
386
|
+
function removeAsset(src) {
|
|
387
|
+
const { srcRel, srcAttr } = getAssetPaths(publicPath, src);
|
|
388
|
+
delete assets[srcRel];
|
|
389
|
+
saveAssets();
|
|
390
|
+
return srcAttr;
|
|
415
391
|
}
|
|
416
392
|
const saveAssets = debounce(() => {
|
|
417
393
|
writeFile(indexPath, assets);
|
|
418
394
|
}, 50);
|
|
419
395
|
const assets = {};
|
|
396
|
+
function onAssetChange(event, absTrg) {
|
|
397
|
+
const src = event === "update" ? updateAsset(absTrg) : removeAsset(absTrg);
|
|
398
|
+
if (socket) {
|
|
399
|
+
socket.send({ event, src });
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
addPlugin(resolve("./runtime/sockets/plugin"));
|
|
403
|
+
const socket = nuxt.options.dev ? await setupSocketServer("content-assets") : null;
|
|
420
404
|
const managers = {};
|
|
421
405
|
for (const [key, source] of Object.entries(sources)) {
|
|
422
406
|
if (options.debug) {
|
|
423
407
|
log(`Creating source "${key}"`);
|
|
424
408
|
}
|
|
425
|
-
managers[key] = makeSourceManager(key, source, publicPath,
|
|
409
|
+
managers[key] = makeSourceManager(key, source, publicPath, onAssetChange);
|
|
426
410
|
}
|
|
427
411
|
nuxt.hook("build:before", async function() {
|
|
428
412
|
for (const [key, manager] of Object.entries(managers)) {
|
|
@@ -434,7 +418,6 @@ const module = defineNuxtModule({
|
|
|
434
418
|
}
|
|
435
419
|
});
|
|
436
420
|
const virtualConfig = [
|
|
437
|
-
// `export const assets = ${JSON.stringify(assets, null, ' ')}`,
|
|
438
421
|
`export const cachePath = '${cachePath}'`
|
|
439
422
|
].join("\n");
|
|
440
423
|
nuxt.hook("nitro:config", async (config) => {
|
package/dist/runtime/config.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare const moduleName = "nuxt-content-assets";
|
|
2
|
-
export declare const moduleKey = "
|
|
2
|
+
export declare const moduleKey = "contentAssets";
|
package/dist/runtime/config.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const moduleName = "nuxt-content-assets";
|
|
2
|
-
export const moduleKey = "
|
|
2
|
+
export const moduleKey = "contentAssets";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export declare const defaults: {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
imageSize: string;
|
|
3
|
+
contentExtensions: string;
|
|
4
|
+
debug: boolean;
|
|
4
5
|
};
|
|
5
|
-
export declare const tags: string[];
|
|
6
6
|
export declare const extensions: {
|
|
7
7
|
image: string[];
|
|
8
8
|
media: string[];
|
|
9
9
|
};
|
|
10
|
+
export declare function getIgnores(extensions: string | string[]): string;
|
package/dist/runtime/options.mjs
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { matchTokens } from "./utils/string.mjs";
|
|
2
2
|
export const defaults = {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// inject image size into the rendered html
|
|
4
|
+
imageSize: "attrs",
|
|
5
|
+
// treat these extensions as content
|
|
6
|
+
contentExtensions: "mdx? csv ya?ml json",
|
|
7
|
+
// output debug messages
|
|
8
|
+
debug: false
|
|
5
9
|
};
|
|
6
|
-
export const tags = ["img", "video", "audio", "source", "embed", "iframe", "a"];
|
|
7
10
|
export const extensions = {
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
// used to get image size
|
|
12
|
+
image: matchTokens("png jpg jpeg gif svg webp ico"),
|
|
13
|
+
// unused for now
|
|
14
|
+
media: matchTokens("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
|
|
10
15
|
};
|
|
16
|
+
export function getIgnores(extensions2) {
|
|
17
|
+
return `^((?!(${matchTokens(extensions2).join("|")})).)*$`;
|
|
18
|
+
}
|
package/dist/runtime/plugin.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import Path from "path";
|
|
2
2
|
import { visit } from "unist-util-visit";
|
|
3
3
|
import { deKey, isValidAsset, toPath, walk } from "./utils/index.mjs";
|
|
4
|
-
import { tags } from "./options.mjs";
|
|
5
4
|
import { cachePath } from "#nuxt-content-assets";
|
|
6
5
|
import { makeStorage } from "./services/index.mjs";
|
|
7
6
|
async function updateAssets() {
|
|
@@ -32,11 +31,14 @@ const plugin = async (nitro) => {
|
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
}, filter);
|
|
35
|
-
visit(file.body, (
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
visit(file.body, (node) => node.type === "element", (node) => {
|
|
35
|
+
for (const [prop, value] of Object.entries(node.props)) {
|
|
36
|
+
if (typeof value !== "string") {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { srcAttr, width, height, ratio } = getAsset(srcDoc, value);
|
|
38
40
|
if (srcAttr) {
|
|
39
|
-
node.props
|
|
41
|
+
node.props[prop] = srcAttr;
|
|
40
42
|
if (width && height) {
|
|
41
43
|
node.props.width = width;
|
|
42
44
|
node.props.height = height;
|
|
@@ -44,12 +46,7 @@ const plugin = async (nitro) => {
|
|
|
44
46
|
if (ratio) {
|
|
45
47
|
node.props.style = `aspect-ratio:${ratio}`;
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
} else if (node.tag === "a") {
|
|
49
|
-
if (node.props.href) {
|
|
50
|
-
const { srcAttr } = getAsset(srcDoc, node.props.href);
|
|
51
|
-
if (srcAttr) {
|
|
52
|
-
node.props.href = srcAttr;
|
|
49
|
+
if (node.tag === "a" && !node.props.target) {
|
|
53
50
|
node.props.target = "_blank";
|
|
54
51
|
}
|
|
55
52
|
}
|
|
@@ -8,11 +8,25 @@ export type AssetConfig = {
|
|
|
8
8
|
query?: string;
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Parse asset paths from absolute path
|
|
12
12
|
*
|
|
13
13
|
* @param srcDir The absolute path to the asset's source folder
|
|
14
14
|
* @param srcAbs The absolute path to the asset itself
|
|
15
|
-
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAssetPaths(srcDir: string, srcAbs: string): {
|
|
17
|
+
id: any;
|
|
18
|
+
srcRel: string;
|
|
19
|
+
srcAttr: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get asset image sizes
|
|
23
|
+
*
|
|
24
|
+
* @param srcAbs The absolute path to the asset itself
|
|
16
25
|
* @param hints A list of named image size hints, i.e. 'style', 'attrs', etc
|
|
17
26
|
*/
|
|
18
|
-
export declare function
|
|
27
|
+
export declare function getAssetSizes(srcAbs: string, hints: string[]): {
|
|
28
|
+
width: number | undefined;
|
|
29
|
+
height: number | undefined;
|
|
30
|
+
ratio: string | undefined;
|
|
31
|
+
query: string | undefined;
|
|
32
|
+
};
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import * as Path from "path";
|
|
2
2
|
import getImageSize from "image-size";
|
|
3
3
|
import { isImage, warn } from "../utils/index.mjs";
|
|
4
|
-
export function
|
|
4
|
+
export function getAssetPaths(srcDir, srcAbs) {
|
|
5
|
+
const srcRel = Path.relative(srcDir, srcAbs);
|
|
6
|
+
const srcAttr = "/" + srcRel;
|
|
7
|
+
const id = srcRel.replaceAll("/", ":");
|
|
8
|
+
return {
|
|
9
|
+
id,
|
|
10
|
+
srcRel,
|
|
11
|
+
srcAttr
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function getAssetSizes(srcAbs, hints) {
|
|
5
15
|
let width = void 0;
|
|
6
16
|
let height = void 0;
|
|
7
17
|
let ratio = void 0;
|
|
@@ -23,8 +33,10 @@ export function getAssetConfig(srcDir, srcAbs, pattern, hints) {
|
|
|
23
33
|
warn(`could not read image "${srcAbs}`);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
return {
|
|
37
|
+
width,
|
|
38
|
+
height,
|
|
39
|
+
ratio,
|
|
40
|
+
query
|
|
41
|
+
};
|
|
30
42
|
}
|
|
@@ -39,11 +39,7 @@ export function createWebSocket() {
|
|
|
39
39
|
logger.warn("Error parsing message:", message.data);
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
handlers.forEach((handler) =>
|
|
43
|
-
if (typeof handler === "function") {
|
|
44
|
-
handler(data);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
42
|
+
handlers.forEach((handler) => handler(data));
|
|
47
43
|
};
|
|
48
44
|
const send = (data) => {
|
|
49
45
|
if (ws) {
|
|
@@ -80,7 +76,9 @@ export function createWebSocket() {
|
|
|
80
76
|
return {
|
|
81
77
|
send,
|
|
82
78
|
addHandler(callback) {
|
|
83
|
-
|
|
79
|
+
if (typeof callback === "function") {
|
|
80
|
+
handlers.push(callback);
|
|
81
|
+
}
|
|
84
82
|
}
|
|
85
83
|
};
|
|
86
84
|
}
|
|
@@ -8,11 +8,10 @@ export default defineNuxtPlugin(async () => {
|
|
|
8
8
|
const { event, src } = data;
|
|
9
9
|
if (src) {
|
|
10
10
|
const isUpdate = event === "update";
|
|
11
|
-
document.querySelectorAll(
|
|
12
|
-
|
|
13
|
-
img.style.opacity = isUpdate ? "1" : "0.2";
|
|
11
|
+
document.querySelectorAll(`:is(img, video, source, embed, iframe):where([src^="${src}"])`).forEach((el) => {
|
|
12
|
+
el.style.opacity = isUpdate ? "1" : "0.2";
|
|
14
13
|
if (isUpdate) {
|
|
15
|
-
|
|
14
|
+
el.setAttribute("src", `${src}?${(/* @__PURE__ */ new Date()).getTime()}`);
|
|
16
15
|
}
|
|
17
16
|
});
|
|
18
17
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Get matched words from a string
|
|
2
|
+
* Get matched tokens (words, expressions) from a string or an array of possible strings
|
|
3
|
+
*
|
|
4
|
+
* Tokens may be separated by space, comma or pipe
|
|
3
5
|
*/
|
|
4
|
-
export declare function
|
|
6
|
+
export declare function matchTokens(value?: string | unknown[]): string[];
|
|
5
7
|
export declare function toPath(key: string): string;
|
|
6
8
|
export declare function toKey(path: string): any;
|
|
7
9
|
export declare function deKey(path: string): string;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export function
|
|
2
|
-
|
|
1
|
+
export function matchTokens(value) {
|
|
2
|
+
const tokens = typeof value === "string" ? value.match(/[^\s,|]+/g) || [] : Array.isArray(value) ? value.filter((value2) => typeof value2 === "string").reduce((output, input) => {
|
|
3
|
+
return [...output, ...matchTokens(input)];
|
|
4
|
+
}, []) : [];
|
|
5
|
+
return Array.from(new Set(tokens));
|
|
3
6
|
}
|
|
4
7
|
export function toPath(key) {
|
|
5
8
|
return key.replaceAll(":", "/");
|
package/dist/types.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { ModuleOptions } from './module'
|
|
3
3
|
|
|
4
4
|
declare module '@nuxt/schema' {
|
|
5
|
-
interface NuxtConfig { ['
|
|
6
|
-
interface NuxtOptions { ['
|
|
5
|
+
interface NuxtConfig { ['contentAssets']?: Partial<ModuleOptions> }
|
|
6
|
+
interface NuxtOptions { ['contentAssets']?: ModuleOptions }
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
|