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 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
- <video src="media/seaside.mp4"></video>
43
+ :video{src="media/seaside.mp4"}
44
44
  ```
45
45
 
46
- The module [processes assets](#how-it-works) and serves them together with your content, adding features such as [image sizing](#image-sizing) and [live-reload](#live-reload).
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
  ![image](image.jpg)
95
- <video src="media/video.mp4" />
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 Item 1
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
- ::ImageGallery{:data="images"}
114
- ::
120
+ :image-gallery{:data="images"}
115
121
  ```
116
122
 
117
- See the Demo for [markup](demo/content/recipes/index.md) and [Demo](demo/components/content/ImageGallery.vue) examples.
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
- From version `0.9.0-alpha` assets are watched and live-reloaded!
127
+ In development, the module watches for asset additions, moves and deletes, and will update the browser live.
122
128
 
123
- Any additions, moves or deletes, or modifications to image content will be updated in the browser automatically.
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
- The module can prevent content jumps by optionally writing image size information to generated `<img>` tags:
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?width=640&height=480" width="640" height="480" style="aspect-ratio:640/480">
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
- For more information see the [configuration](#image-size) section and [Demo](demo/components/temp/ProseImg.vue) for an example.
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
- ```html
166
- <a href="...">
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
- You can configure the module like so:
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
- 'content-assets': {
183
- // use aspect-ratio rather than attributes
174
+ contentAssets: {
175
+ // inject image sizes into the rendered html
184
176
  imageSize: 'style',
185
177
 
186
- // print debug messages to the console
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 the `?width=...&height=...` query string to image frontmatter variables |
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
- output?: string;
5
- imageSize?: string;
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
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "nuxt-content-assets",
3
- "configKey": "content-assets",
3
+ "configKey": "contentAssets",
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "0.9.0-beta"
7
+ "version": "0.10.0"
8
8
  }
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 { hash } from 'ohash';
10
+ import 'ohash';
11
11
  import { listen } from 'listhen';
12
12
  import { WebSocketServer, WebSocket } from 'ws';
13
13
 
14
- function matchWords(value) {
15
- return typeof value === "string" ? value.match(/\w+/g) || [] : [];
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$1 = {
25
- assetsDir: "/assets/",
26
- assetsPattern: "[path]/[file]"
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
- image: matchWords("png jpg jpeg gif svg webp ico"),
30
- media: matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
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 = "content-assets";
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 getAssetConfig(srcDir, srcAbs, pattern, hints) {
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
- const srcRel = Path.relative(srcDir, srcAbs);
111
- const srcAttr = "/" + srcRel;
112
- const id = srcRel.replaceAll("/", ":");
113
- return { id, srcRel, srcAttr, width, height, ratio, query };
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 { server, url } = await listen(() => "Nuxt Sockets", defaults);
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
- nuxt.options.content?.ignores.push("^((?!(mdx?|json|ya?ml|csv)).)*$");
362
- const output = options.output || defaults$1.assetsDir;
363
- const matches = output.match(/([^[]+)(.*)?/);
364
- const assetsPattern = (matches ? matches[2] : "") || defaults$1.assetsPattern;
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(output2, sources2);
359
+ Object.assign(output, sources2);
370
360
  }
371
- return output2;
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
- srcRel,
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 watchAsset(event, absTrg) {
411
- const src = event === "update" ? updateAsset(absTrg) : removeAsset(absTrg);
412
- if (socket) {
413
- socket.send({ event, src });
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, watchAsset);
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) => {
@@ -1,2 +1,2 @@
1
1
  export declare const moduleName = "nuxt-content-assets";
2
- export declare const moduleKey = "content-assets";
2
+ export declare const moduleKey = "contentAssets";
@@ -1,2 +1,2 @@
1
1
  export const moduleName = "nuxt-content-assets";
2
- export const moduleKey = "content-assets";
2
+ export const moduleKey = "contentAssets";
@@ -1,9 +1,10 @@
1
1
  export declare const defaults: {
2
- assetsDir: string;
3
- assetsPattern: string;
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;
@@ -1,10 +1,18 @@
1
- import { matchWords } from "./utils/string.mjs";
1
+ import { matchTokens } from "./utils/string.mjs";
2
2
  export const defaults = {
3
- assetsDir: "/assets/",
4
- assetsPattern: "[path]/[file]"
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
- image: matchWords("png jpg jpeg gif svg webp ico"),
9
- media: matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd")
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
+ }
@@ -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, (n) => tags.includes(n.tag), (node) => {
36
- if (node.props.src) {
37
- const { srcAttr, width, height, ratio } = getAsset(srcDoc, node.props.src);
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.src = srcAttr;
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
- * Get config for asset
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
- * @param pattern The user-defined pattern to create the public src attribute
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 getAssetConfig(srcDir: string, srcAbs: string, pattern: string, hints: string[]): AssetConfig;
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 getAssetConfig(srcDir, srcAbs, pattern, hints) {
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
- const srcRel = Path.relative(srcDir, srcAbs);
27
- const srcAttr = "/" + srcRel;
28
- const id = srcRel.replaceAll("/", ":");
29
- return { id, srcRel, srcAttr, width, height, ratio, query };
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
- handlers.push(callback);
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(`img[src^="${src}"]`).forEach((el) => {
12
- const img = el;
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
- img.setAttribute("src", `${src}?${(/* @__PURE__ */ new Date()).getTime()}`);
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 matchWords(value?: string): string[];
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 matchWords(value) {
2
- return typeof value === "string" ? value.match(/\w+/g) || [] : [];
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 { ['content-assets']?: Partial<ModuleOptions> }
6
- interface NuxtOptions { ['content-assets']?: ModuleOptions }
5
+ interface NuxtConfig { ['contentAssets']?: Partial<ModuleOptions> }
6
+ interface NuxtOptions { ['contentAssets']?: ModuleOptions }
7
7
  }
8
8
 
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-content-assets",
3
- "version": "0.9.0-beta",
3
+ "version": "0.10.0",
4
4
  "description": "Enable locally-located assets in Nuxt Content",
5
5
  "repository": "davestewart/nuxt-content-assets",
6
6
  "license": "MIT",