nuxt-content-assets 0.5.1 → 0.5.2

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
@@ -53,7 +53,7 @@ To run the demo online, go to:
53
53
 
54
54
  You can browse the demo files in:
55
55
 
56
- - .https://github.com/davestewart/nuxt-content-assets/tree/main/demo
56
+ - https://github.com/davestewart/nuxt-content-assets/tree/main/demo
57
57
 
58
58
  To run the demo locally, clone the application and from the root, run:
59
59
 
@@ -74,7 +74,7 @@ Configure `nuxt.config.ts`:
74
74
  ```js
75
75
  export default defineNuxtConfig({
76
76
  modules: [
77
- 'nuxt-content-relative-assets', // make sure to add before content!
77
+ 'nuxt-content-assets', // make sure to add before content!
78
78
  '@nuxt/content',
79
79
  ]
80
80
  })
@@ -111,21 +111,28 @@ See the [configuration](#output) section for more options.
111
111
 
112
112
  ### Images
113
113
 
114
- The module [optionally](#image-attributes) writes `width` and `height` attributes to the generated HTML:
114
+ The module can [optionally](#image-attributes) write `width`, `height` and `aspect-ratio` information to generated `<img>` tags:
115
115
 
116
116
  ```html
117
- <img src="..." width="640" height="480">
117
+ <img src="..." width="640" height="480" style="aspect-ratio:640/480">
118
118
  ```
119
119
 
120
- This locks the aspect ratio of the image preventing content jumps.
120
+ This can prevent content jumps on page load. If you add `attributes` only, include the following CSS in your app:
121
121
 
122
- If you use custom [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can even grab these values using the Vue `$attrs` property:
122
+ ```css
123
+ img {
124
+ max-width: 100%;
125
+ height: auto;
126
+ }
127
+ ```
128
+
129
+ If you use custom [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can use these values in your own markup:
123
130
 
124
131
  ```vue
125
132
  <template>
126
- <div class="image">
127
- <img :src="$attrs.src" :style="`aspect-ratio:${$attrs.width}/${$attrs.height}`" />
128
- </div>
133
+ <span class="image">
134
+ <img :src="$attrs.src" :style="$attrs.style" />
135
+ </span>
129
136
  </template>
130
137
 
131
138
  <script>
@@ -154,8 +161,8 @@ export default defineNuxtConfig({
154
161
  // completely replace supported extensions
155
162
  extensions: 'png jpg',
156
163
 
157
- // add image width and height
158
- imageAttrs: true,
164
+ // use aspect-ratio rather than attributes
165
+ imageSize: 'ratio',
159
166
 
160
167
  // print debug messages to the console
161
168
  debug: true,
@@ -168,7 +175,7 @@ export default defineNuxtConfig({
168
175
  The output path can be customised using a template string:
169
176
 
170
177
  ```
171
- assets/img/content/[path]/[name][extname]
178
+ assets/content/[name]-[hash].[ext]
172
179
  ```
173
180
 
174
181
  The first part of the path should be public root-relative folder:
@@ -177,7 +184,7 @@ The first part of the path should be public root-relative folder:
177
184
  assets/img/content
178
185
  ```
179
186
 
180
- The optional second part of the path indicates specific placement of each image:
187
+ The optional second part of the path indicates the relative location of each image:
181
188
 
182
189
  | Token | Description | Example |
183
190
  |-------------|--------------------------------------------|--------------------|
@@ -196,15 +203,15 @@ For example:
196
203
  | `assets/img/[name]-[hash].[ext]` | `assets/img/featured-9M00N4l9A0.jpg` |
197
204
  | `content/[hash].[ext]` | `content/9M00N4l9A0.jpg` |
198
205
 
199
- Note that the module defaults to all files in a single folder:
206
+ Note that the module defaults to:
200
207
 
201
208
  ```
202
- /assets/content/[name]-[hash].[ext]
209
+ /assets/content/[folder]/[file]
203
210
  ```
204
211
 
205
212
  ### Extensions
206
213
 
207
- You can add or replace supported extensions if you need to:
214
+ You can add (or replace) supported extensions if you need to:
208
215
 
209
216
  To add extensions, use `additionalExtensions`:
210
217
 
@@ -214,26 +221,36 @@ To add extensions, use `additionalExtensions`:
214
221
  }
215
222
  ```
216
223
 
217
- To completely replace supported extensions, use `extensions`:
224
+ To replace extensions, use `extensions`:
218
225
 
219
226
  ```ts
220
227
  {
221
- extensions: 'png jpg' // serve png and jpg files only
228
+ extensions: 'png jpg' // serve png and jpg files only
222
229
  }
223
230
  ```
224
231
 
225
232
  ### Image attributes
226
233
 
227
- The module automatically adds `width` and `height` attributes to images.
234
+ You can add image size hints to the generated images.
235
+
236
+ To add `style` aspect-ratio:
237
+
238
+ ```ts
239
+ {
240
+ imageSize: 'style'
241
+ }
242
+ ```
228
243
 
229
- Opt out of this by passing `false`:
244
+ To add `width` and `height` attributes:
230
245
 
231
246
  ```ts
232
247
  {
233
- imageAttrs: false
248
+ imageSize: 'attrs'
234
249
  }
235
250
  ```
236
251
 
252
+ You can even add both if you need to.
253
+
237
254
  ## Development
238
255
 
239
256
  Should you wish to develop the project, the scripts are:
package/dist/module.d.ts CHANGED
@@ -4,7 +4,7 @@ interface ModuleOptions {
4
4
  output?: string;
5
5
  additionalExtensions?: string;
6
6
  extensions?: string;
7
- imageAttrs?: boolean;
7
+ imageSize?: string;
8
8
  debug?: boolean;
9
9
  }
10
10
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "content-assets",
2
+ "name": "nuxt-content-assets",
3
3
  "configKey": "content-assets",
4
- "version": "0.5.1"
4
+ "version": "0.5.2"
5
5
  }
package/dist/module.mjs CHANGED
@@ -6,8 +6,37 @@ import * as Path from 'path';
6
6
  import Path__default from 'path';
7
7
  import { hash } from 'ohash';
8
8
 
9
+ function getSources(sources) {
10
+ return Object.keys(sources).reduce((output, key) => {
11
+ const source = sources[key];
12
+ if (source) {
13
+ const { driver, base } = source;
14
+ if (driver === "fs") {
15
+ output[key] = base;
16
+ }
17
+ }
18
+ return output;
19
+ }, {});
20
+ }
21
+
22
+ const defaults = {
23
+ assetsDir: "assets/content",
24
+ assetsPattern: "[folder]/[file]"
25
+ };
26
+ const imageExtensions = matchWords("png jpg jpeg gif svg webp ico");
27
+ const mediaExtensions = matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd");
28
+ const fileExtensions = matchWords("pdf doc docx xls xlsx ppt pptx odp key");
29
+ const extensions = [
30
+ ...imageExtensions,
31
+ ...mediaExtensions,
32
+ ...fileExtensions
33
+ ];
34
+
35
+ const moduleName = "nuxt-content-assets";
36
+ const moduleKey = "content-assets";
37
+
9
38
  function log(...data) {
10
- console.info(`[${name}]`, ...data);
39
+ console.info(`[${moduleKey}]`, ...data);
11
40
  }
12
41
 
13
42
  function matchWords(value) {
@@ -39,48 +68,22 @@ const replacers = {
39
68
  hash: (src) => hash({ src })
40
69
  };
41
70
 
42
- const name = "content-assets";
43
- const defaults = {
44
- assetsDir: "assets/content",
45
- assetsPattern: "[name]-[hash].[ext]"
46
- };
47
- const imageExtensions = matchWords("png jpg jpeg gif svg webp ico");
48
- const mediaExtensions = matchWords("mp3 m4a wav mp4 mov webm ogg avi flv avchd");
49
- const fileExtensions = matchWords("pdf doc docx xls xlsx ppt pptx odp key");
50
- const extensions = [
51
- ...imageExtensions,
52
- ...mediaExtensions,
53
- ...fileExtensions
54
- ];
55
-
56
- function getSources(sources) {
57
- return Object.keys(sources).reduce((output, key) => {
58
- const source = sources[key];
59
- if (source) {
60
- const { driver, base } = source;
61
- if (driver === "fs") {
62
- output[key] = base;
63
- }
64
- }
65
- return output;
66
- }, {});
67
- }
68
-
69
71
  const resolve = createResolver(import.meta.url).resolve;
70
72
  const module = defineNuxtModule({
71
73
  meta: {
72
- name
74
+ name: moduleName,
75
+ configKey: moduleKey
73
76
  },
74
77
  defaults: {
75
78
  output: `${defaults.assetsDir}/${defaults.assetsPattern}`,
76
79
  extensions: "",
77
80
  additionalExtensions: "",
78
- imageAttrs: true,
81
+ imageSize: "",
79
82
  debug: false
80
83
  },
81
84
  setup(options, nuxt) {
82
85
  var _a;
83
- const pluginPath = resolve("./runtime/server") + "/plugins/plugin";
86
+ const pluginPath = resolve("./runtime/plugin");
84
87
  const buildPath = nuxt.options.buildDir;
85
88
  const cachePath = Path.resolve(buildPath, "content-assets");
86
89
  if (options.debug) {
@@ -116,16 +119,22 @@ const module = defineNuxtModule({
116
119
  function getAssetConfig(pattern, src, dir) {
117
120
  let width = void 0;
118
121
  let height = void 0;
119
- if (options.imageAttrs && isImage(src)) {
122
+ let ratio = "";
123
+ if (options.imageSize && isImage(src)) {
120
124
  const size = getImageSize(src);
121
- width = size.width;
122
- height = size.height;
125
+ if (options.imageSize.includes("style")) {
126
+ ratio = `${size.width}/${size.height}`;
127
+ }
128
+ if (options.imageSize.includes("attrs")) {
129
+ width = size.width;
130
+ height = size.height;
131
+ }
123
132
  }
124
133
  const id = Path.join(Path.basename(dir), Path.relative(dir, src)).replaceAll("/", ":");
125
134
  const file = interpolatePattern(pattern, src, dir);
126
135
  const trg = Path.join(cachePath, assetsDir, file);
127
136
  const rel = Path.join("/", assetsDir, file);
128
- return { id, file, trg, rel, width, height };
137
+ return { id, file, trg, rel, width, height, ratio };
129
138
  }
130
139
  const publicFolder = Path.join(cachePath, assetsDir);
131
140
  const sourceFolders = Object.values(sources);
@@ -159,15 +168,15 @@ ${paths.join("\n")}
159
168
  `export const assets = ${JSON.stringify(assets)}`,
160
169
  `export const sources = ${JSON.stringify(sources)}`
161
170
  ].join("\n");
162
- nuxt.options.alias[`#${name}`] = addTemplate({
163
- filename: `${name}.mjs`,
171
+ nuxt.options.alias[`#${moduleName}`] = addTemplate({
172
+ filename: `${moduleName}.mjs`,
164
173
  getContents: () => virtualConfig
165
174
  }).dst;
166
175
  nuxt.hook("nitro:config", async (config) => {
167
176
  config.plugins || (config.plugins = []);
168
177
  config.plugins.push(pluginPath);
169
178
  config.virtual || (config.virtual = {});
170
- config.virtual[`#${name}`] = virtualConfig;
179
+ config.virtual[`#${moduleName}`] = virtualConfig;
171
180
  config.publicAssets || (config.publicAssets = []);
172
181
  config.publicAssets.push({
173
182
  dir: cachePath
@@ -0,0 +1,9 @@
1
+ export declare const defaults: {
2
+ assetsDir: string;
3
+ assetsPattern: string;
4
+ };
5
+ export declare const imageExtensions: RegExpMatchArray | [];
6
+ export declare const mediaExtensions: RegExpMatchArray | [];
7
+ export declare const fileExtensions: RegExpMatchArray | [];
8
+ export declare const extensions: string[];
9
+ export declare const tags: string[];
@@ -0,0 +1,14 @@
1
+ import { matchWords } from "./utils/assets.mjs";
2
+ export const defaults = {
3
+ assetsDir: "assets/content",
4
+ assetsPattern: "[folder]/[file]"
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
+ export const tags = ["img", "video", "audio", "source", "embed", "iframe", "a"];
@@ -1,8 +1,8 @@
1
1
  import Path from "path";
2
2
  import { visit } from "unist-util-visit";
3
- import { assets, sources } from "#content-assets";
4
- import { tags } from "../../../config";
5
- import { isValidAsset, walk } from "../../../utils";
3
+ import { isValidAsset, walk } from "./utils/index.mjs";
4
+ import { tags } from "./options.mjs";
5
+ import { assets, sources } from "#nuxt-content-assets";
6
6
  function getDocPath(id) {
7
7
  const parts = id.split(":");
8
8
  const key = parts.shift();
@@ -29,7 +29,7 @@ export default defineNitroPlugin(async (nitroApp) => {
29
29
  }, filter);
30
30
  visit(file.body, (n) => tags.includes(n.tag), (node) => {
31
31
  if (node.props.src) {
32
- const { rel, width, height } = getAsset(absDoc, node.props.src);
32
+ const { rel, width, height, ratio } = getAsset(absDoc, node.props.src);
33
33
  if (rel) {
34
34
  node.props.src = rel;
35
35
  }
@@ -37,6 +37,9 @@ export default defineNitroPlugin(async (nitroApp) => {
37
37
  node.props.width = width;
38
38
  node.props.height = height;
39
39
  }
40
+ if (ratio) {
41
+ node.props.style = `aspect-ratio:${ratio}`;
42
+ }
40
43
  } else if (node.tag === "a") {
41
44
  if (node.props.href) {
42
45
  const { rel } = getAsset(absDoc, node.props.href);
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Get matched words from a string
3
+ */
4
+ export declare function matchWords(value: string): RegExpMatchArray | [];
5
+ /**
6
+ * Test path to be relative
7
+ */
8
+ export declare function isRelative(path: string): boolean;
9
+ /**
10
+ * Test path for image extension
11
+ */
12
+ export declare function isImage(path: string): boolean;
13
+ /**
14
+ * Test path for asset extension
15
+ */
16
+ export declare function isAsset(path: string): boolean;
17
+ /**
18
+ * Test if value is a valid asset
19
+ */
20
+ export declare function isValidAsset(value?: string): boolean;
21
+ /**
22
+ * Interpolate assets path pattern
23
+ *
24
+ * @param pattern A path pattern with tokens
25
+ * @param src The absolute path to a src asset
26
+ * @param dir The absolute path to its containing folder
27
+ * @param warn An optional flag to warn for unknown tokens
28
+ */
29
+ export declare function interpolatePattern(pattern: string, src: string, dir: string, warn?: boolean): any;
30
+ /**
31
+ * Hash of replacer functions
32
+ */
33
+ export declare const replacers: Record<string, Function>;
@@ -0,0 +1,42 @@
1
+ import Path from "path";
2
+ import { hash as ohash } from "ohash";
3
+ import { extensions, imageExtensions } from "../options.mjs";
4
+ import { log } from "./debug.mjs";
5
+ export function matchWords(value) {
6
+ return value.match(/\w+/g) || [];
7
+ }
8
+ export function isRelative(path) {
9
+ return !(path.startsWith("http") || Path.isAbsolute(path));
10
+ }
11
+ export function isImage(path) {
12
+ const ext = Path.extname(path).substring(1);
13
+ return imageExtensions.includes(ext);
14
+ }
15
+ export function isAsset(path) {
16
+ const ext = Path.extname(path).substring(1);
17
+ return extensions.includes(ext);
18
+ }
19
+ export function isValidAsset(value) {
20
+ return typeof value === "string" && isAsset(value) && isRelative(value);
21
+ }
22
+ export function interpolatePattern(pattern, src, dir, warn = false) {
23
+ return Path.join(pattern.replace(/\[\w+]/g, (match) => {
24
+ const name = match.substring(1, match.length - 1);
25
+ const fn = replacers[name];
26
+ if (fn) {
27
+ return fn(src, dir);
28
+ }
29
+ if (warn) {
30
+ log(`Unknown output token ${match}`, true);
31
+ }
32
+ return match;
33
+ }));
34
+ }
35
+ export const replacers = {
36
+ folder: (src, dir) => Path.dirname(src.replace(dir, "")),
37
+ file: (src) => Path.basename(src),
38
+ name: (src) => Path.basename(src, Path.extname(src)),
39
+ extname: (src) => Path.extname(src),
40
+ ext: (src) => Path.extname(src).substring(1),
41
+ hash: (src) => ohash({ src })
42
+ };
@@ -0,0 +1,7 @@
1
+ import type { MountOptions } from '@nuxt/content';
2
+ /**
3
+ * Get content source folders
4
+ *
5
+ * @param sources
6
+ */
7
+ export declare function getSources(sources: Record<string, MountOptions>): Record<string, string>;
@@ -0,0 +1,12 @@
1
+ export function getSources(sources) {
2
+ return Object.keys(sources).reduce((output, key) => {
3
+ const source = sources[key];
4
+ if (source) {
5
+ const { driver, base } = source;
6
+ if (driver === "fs") {
7
+ output[key] = base;
8
+ }
9
+ }
10
+ return output;
11
+ }, {});
12
+ }
@@ -0,0 +1,2 @@
1
+ export declare function log(...data: any[]): void;
2
+ export declare function warn(...data: any[]): void;
@@ -0,0 +1,7 @@
1
+ import { moduleKey } from "../../config";
2
+ export function log(...data) {
3
+ console.info(`[${moduleKey}]`, ...data);
4
+ }
5
+ export function warn(...data) {
6
+ console.warn(`[${moduleKey}]`, ...data);
7
+ }
@@ -0,0 +1,4 @@
1
+ export * from './content';
2
+ export * from './object';
3
+ export * from './assets';
4
+ export * from './debug';
@@ -0,0 +1,4 @@
1
+ export * from "./content.mjs";
2
+ export * from "./object.mjs";
3
+ export * from "./assets.mjs";
4
+ export * from "./debug.mjs";
@@ -0,0 +1,10 @@
1
+ export type Callback = (value: any, parent?: any, key?: string | number) => void;
2
+ export type Filter = (value: any, key?: string | number) => boolean | void;
3
+ /**
4
+ * Walk an object structure
5
+ *
6
+ * @param node
7
+ * @param callback
8
+ * @param filter
9
+ */
10
+ export declare function walk(node: any, callback: Callback, filter?: Filter): void;
@@ -0,0 +1,22 @@
1
+ export function walk(node, callback, filter) {
2
+ function visit(node2, callback2, parent, key) {
3
+ if (filter) {
4
+ const result = filter(node2, key);
5
+ if (result === false) {
6
+ return;
7
+ }
8
+ }
9
+ if (Array.isArray(node2)) {
10
+ node2.forEach((value, index) => {
11
+ visit(value, callback2, node2, index);
12
+ });
13
+ } else if (typeof node2 === "object" && node2 !== null) {
14
+ Object.keys(node2).forEach((key2) => {
15
+ visit(node2[key2], callback2, node2, key2);
16
+ });
17
+ } else {
18
+ callback2(node2, parent, key);
19
+ }
20
+ }
21
+ visit(node, callback);
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-content-assets",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Enable locally-located assets in Nuxt Content",
5
5
  "repository": "davestewart/nuxt-content-assets",
6
6
  "license": "MIT",