nuxt-content-assets 1.0.0 → 1.1.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
@@ -47,16 +47,19 @@ At build time the module [collates and serves](#how-it-works) assets and content
47
47
 
48
48
  ### Features
49
49
 
50
+ Built on top of [Nuxt Content](https://github.com/nuxt/content/) and compatible with any Nuxt Content project or theme, including [Docus](https://github.com/nuxt-themes/docus).
51
+
50
52
  User experience:
51
53
 
52
54
  - co-locate assets with content files
53
- - write relative paths to see preview in editor
55
+ - reference assets using relative paths
56
+ - supports any format (image, video, doc)
54
57
 
55
58
  Developer experience:
56
59
 
57
- - works for tags and custom components
60
+ - works with tags and custom components
58
61
  - works in markdown and frontmatter
59
- - file watching and live reload
62
+ - file watching and asset live-reload
60
63
  - image size injection
61
64
  - zero config
62
65
 
@@ -147,17 +150,23 @@ If you edit an image, video, embed or iframe source, the content will update imm
147
150
 
148
151
  ### Image sizing
149
152
 
150
- You can [configure](#image-size) the module to add image size attributes to generated `<img>` tags:
153
+ #### HTML
154
+
155
+ The module is [preconfigured](#image-size) to pass image size hints (by default `style`) to generated `<img>` tags:
151
156
 
152
157
  ```html
153
- <img src="/image.jpg"
154
- style="aspect-ratio:640/480"
155
- width="640"
156
- height="480"
157
- >
158
+ <!-- imageSize: 'style' -->
159
+ <img src="/image.jpg" style="aspect-ratio:640/480">
160
+
161
+ <!-- imageSize: 'attrs' -->
162
+ <img src="/image.jpg" width="640" height="480">
158
163
  ```
159
164
 
160
- 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:
165
+ Passing image sizes prevents content jumps on page load.
166
+
167
+ #### Prose components
168
+
169
+ If you use [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can use `imageSize: 'attrs'` to [hook into these values](demo/components/temp/ProseImg.vue) via Vue's `$attrs` property:
161
170
 
162
171
  ```vue
163
172
  <template>
@@ -173,12 +182,22 @@ export default {
173
182
  </script>
174
183
  ```
175
184
 
176
- 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:
185
+ #### Frontmatter
186
+
187
+ If you pass [frontmatter](demo/content/advanced/gallery.md) to [custom components](demo/components/content/ContentImage.vue) configure `imageSize` as `'src'` to encode the size in `src`:
177
188
 
178
189
  ```
179
- :image-gallery={:data="images"}
190
+ :image-content{:src="image"}
180
191
  ```
181
192
 
193
+ The component will receive the updated path which you can parse and implement as you see fit.
194
+
195
+ ```html
196
+ <img class="image-content" src="/image.jpg?width=640&height=480">
197
+ ```
198
+
199
+ See demo component [here](demo/components/content/ContentImage.vue).
200
+
182
201
  ## Configuration
183
202
 
184
203
  The module can be configured in your Nuxt configuration file:
@@ -205,19 +224,19 @@ You can add one or more image size hints to the generated images:
205
224
 
206
225
  ```ts
207
226
  {
208
- imageSize: 'attrs url'
227
+ imageSize: 'style attrs src'
209
228
  }
210
229
  ```
211
230
 
212
231
  Pick from the following switches:
213
232
 
214
- | Switch | What it does |
215
- |---------|---------------------------------------------------------------------------|
216
- | `style` | Adds `style="aspect-ratio:..."` to any `<img>` tag |
217
- | `attrs` | Adds `width` and `height` attributes to any `<img>` tag |
218
- | `url` | Adds a `?width=...&height=...` query string to image paths in frontmatter |
233
+ | Switch | What it does |
234
+ | ------- | ------------------------------------------------------------ |
235
+ | `style` | Adds `style="aspect-ratio:..."` to any `<img>` tag |
236
+ | `attrs` | Adds `width` and `height` attributes to any `<img>` tag |
237
+ | `src` | Adds `?width=...&height=...` to `src` attribute (frontmatter only) |
219
238
 
220
- Note: if you add `attrs` only, include the following CSS in your app:
239
+ Note: if you add *only* `attrs` include the following CSS in your app:
221
240
 
222
241
  ```css
223
242
  img {
@@ -226,6 +245,8 @@ img {
226
245
  }
227
246
  ```
228
247
 
248
+ To disable, pass `false`.
249
+
229
250
  ### Content extensions
230
251
 
231
252
  This setting tells Nuxt Content to ignore anything that is **not** one of these file extensions:
package/dist/module.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
 
3
3
  interface ModuleOptions {
4
- imageSize?: string | string[];
4
+ imageSize?: string | string[] | false;
5
5
  contentExtensions: string | string[];
6
6
  debug?: boolean;
7
7
  }
package/dist/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "1.0.0"
7
+ "version": "1.1.0"
8
8
  }
package/dist/module.mjs CHANGED
@@ -51,6 +51,9 @@ function getIgnores(extensions2) {
51
51
  return `^((?!(${matchTokens(extensions2).join("|")})).)*$`;
52
52
  }
53
53
 
54
+ function removeQuery(path) {
55
+ return path.replace(/\?.*$/, "");
56
+ }
54
57
  function isExcluded(path) {
55
58
  return path.split("/").some((segment) => segment.startsWith(".") || segment.startsWith("_"));
56
59
  }
@@ -59,7 +62,7 @@ function isImage(path) {
59
62
  return extensions.image.includes(ext);
60
63
  }
61
64
  function isArticle(path) {
62
- return path.endsWith(".md");
65
+ return removeQuery(path).endsWith(".md");
63
66
  }
64
67
  function isAsset(path) {
65
68
  return !isArticle(path);
@@ -131,8 +134,8 @@ function getAssetSizes(srcAbs, hints) {
131
134
  if (hints.includes("style")) {
132
135
  ratio = `${size.width}/${size.height}`;
133
136
  }
134
- if (hints.includes("url")) {
135
- query = `?width=${size.width}&height=${size.height}`;
137
+ if (hints.includes("src") || hints.includes("url")) {
138
+ query = `width=${size.width}&height=${size.height}`;
136
139
  }
137
140
  } catch (err) {
138
141
  warn(`could not read image "${srcAbs}`);
@@ -1,6 +1,17 @@
1
1
  import Path from "path";
2
2
  import { visit, SKIP, CONTINUE } from "unist-util-visit";
3
- import { deKey, isValidAsset, list, matchTokens, toPath, walk } from "./utils/index.mjs";
3
+ import {
4
+ buildStyle,
5
+ deKey,
6
+ isValidAsset,
7
+ list,
8
+ matchTokens,
9
+ toPath,
10
+ walk,
11
+ removeQuery,
12
+ buildQuery,
13
+ parseQuery
14
+ } from "./utils/index.mjs";
4
15
  import { debug, cachePath } from "#nuxt-content-assets";
5
16
  import { makeStorage } from "./services/index.mjs";
6
17
  async function updateAssets() {
@@ -51,10 +62,11 @@ const plugin = async (nitro) => {
51
62
  const filter = (value, key) => !(String(key).startsWith("_") || key === "body");
52
63
  walk(file, (value, parent, key) => {
53
64
  if (isValidAsset(value)) {
54
- const { srcAttr, query } = getAsset(value);
65
+ const { srcAttr, query } = getAsset(removeQuery(value));
55
66
  if (srcAttr) {
56
- parent[key] = srcAttr + (query || "");
57
- updated.push(`meta: ${key} to "${srcAttr}"`);
67
+ const srcUrl = query ? buildQuery(srcAttr, parseQuery(value), query) : srcAttr;
68
+ parent[key] = srcUrl;
69
+ updated.push(`meta: ${key} to "${srcUrl}"`);
58
70
  }
59
71
  }
60
72
  }, filter);
@@ -82,7 +94,7 @@ const plugin = async (nitro) => {
82
94
  }
83
95
  if (ratio) {
84
96
  if (typeof node.props.style === "string") {
85
- node.props.style += `; aspect-ratio: ${ratio};`;
97
+ node.props.style = buildStyle(node.props.style, `aspect-ratio: ${ratio}`);
86
98
  } else {
87
99
  node.props.style ||= {};
88
100
  node.props.style.aspectRatio = ratio;
@@ -22,7 +22,7 @@ export declare function getAssetPaths(srcDir: string, srcAbs: string): {
22
22
  * Get asset image sizes
23
23
  *
24
24
  * @param srcAbs The absolute path to the asset itself
25
- * @param hints A list of named image size hints, i.e. 'style', 'attrs', etc
25
+ * @param hints A list of named image size hints, one of 'attrs', 'style', or 'src'
26
26
  */
27
27
  export declare function getAssetSizes(srcAbs: string, hints: string[]): {
28
28
  width: number | undefined;
@@ -26,8 +26,8 @@ export function getAssetSizes(srcAbs, hints) {
26
26
  if (hints.includes("style")) {
27
27
  ratio = `${size.width}/${size.height}`;
28
28
  }
29
- if (hints.includes("url")) {
30
- query = `?width=${size.width}&height=${size.height}`;
29
+ if (hints.includes("src") || hints.includes("url")) {
30
+ query = `width=${size.width}&height=${size.height}`;
31
31
  }
32
32
  } catch (err) {
33
33
  warn(`could not read image "${srcAbs}`);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Build a style string by passing multiple independent expressions
3
+ */
4
+ export declare function buildStyle(...expr: string[]): string;
5
+ /**
6
+ * Build a query string by passing multiple independent expressions
7
+ */
8
+ export declare function buildQuery(...expr: string[]): string;
@@ -0,0 +1,12 @@
1
+ export function buildStyle(...expr) {
2
+ return expr.map((expr2) => expr2.replace(/^[; ]+|[; ]+$/g, "")).filter((s) => s).join(";").replace(/\s*;\s*/g, "; ") + ";";
3
+ }
4
+ export function buildQuery(...expr) {
5
+ const output = expr.map((expr2) => expr2.replace(/^[?&]+|&+$/g, "")).filter((s) => s);
6
+ if (output.length) {
7
+ const [first, ...rest] = output;
8
+ const isParam = (expr2) => /^[^?]+=[^=]+$/.test(expr2);
9
+ return !isParam(first) ? rest.length > 0 ? first + (first.includes("?") ? "&" : "?") + rest.join("&") : first : "?" + output.join("&");
10
+ }
11
+ return "";
12
+ }
@@ -1,5 +1,6 @@
1
- export * from './assert';
1
+ export * from './path';
2
2
  export * from './debug';
3
+ export * from './build';
3
4
  export * from './fs';
4
5
  export * from './string';
5
6
  export * from './object';
@@ -1,5 +1,6 @@
1
- export * from "./assert.mjs";
1
+ export * from "./path.mjs";
2
2
  export * from "./debug.mjs";
3
+ export * from "./build.mjs";
3
4
  export * from "./fs.mjs";
4
5
  export * from "./string.mjs";
5
6
  export * from "./object.mjs";
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Parses the query string from a path
3
+ */
4
+ export declare function parseQuery(path: string): string;
5
+ /**
6
+ * Removes the query string from a path
7
+ */
8
+ export declare function removeQuery(path: string): string;
1
9
  /**
2
10
  * Test path to be relative
3
11
  */
@@ -1,5 +1,12 @@
1
1
  import Path from "path";
2
2
  import { extensions } from "../options.mjs";
3
+ export function parseQuery(path) {
4
+ const matches = path.match(/\?.+$/);
5
+ return matches ? matches[0] : "";
6
+ }
7
+ export function removeQuery(path) {
8
+ return path.replace(/\?.*$/, "");
9
+ }
3
10
  export function isRelative(path) {
4
11
  return !(path.startsWith("http") || Path.isAbsolute(path));
5
12
  }
@@ -11,7 +18,7 @@ export function isImage(path) {
11
18
  return extensions.image.includes(ext);
12
19
  }
13
20
  export function isArticle(path) {
14
- return path.endsWith(".md");
21
+ return removeQuery(path).endsWith(".md");
15
22
  }
16
23
  export function isAsset(path) {
17
24
  return !isArticle(path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-content-assets",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Enable locally-located assets in Nuxt Content",
5
5
  "repository": "davestewart/nuxt-content-assets",
6
6
  "license": "MIT",
@@ -33,7 +33,6 @@
33
33
  "dependencies": {
34
34
  "@nuxt/kit": "^3.3.2",
35
35
  "debounce": "^1.2.1",
36
- "glob": "^9.3.2",
37
36
  "image-size": "^1.0.2",
38
37
  "listhen": "^1.0.4",
39
38
  "ohash": "^1.0.0",