nuxt-content-assets 1.3.7 → 1.4.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
@@ -8,7 +8,7 @@
8
8
  > Enable locally-located assets in Nuxt Content
9
9
 
10
10
  <p align="center">
11
- <img src="https://raw.githubusercontent.com/davestewart/nuxt-content-assets/main/demo/content/splash.png" alt="Nuxt Content Assets logo">
11
+ <img src="https://raw.githubusercontent.com/davestewart/nuxt-content-assets/main/playground/content/splash.png" alt="Nuxt Content Assets logo">
12
12
  </p>
13
13
 
14
14
  ## Overview
@@ -63,26 +63,28 @@ Developer experience:
63
63
  - image size injection
64
64
  - zero config
65
65
 
66
- ## Demo
66
+ ## Playground
67
67
 
68
- To clone and run the demo locally:
68
+ To test the module before installing, you can try out the Nuxt Content Assets playground.
69
+
70
+ To clone and run locally:
69
71
 
70
72
  ```bash
71
73
  git clone https://github.com/davestewart/nuxt-content-assets.git
72
74
  cd nuxt-content-assets
73
- npm install && npm install --prefix ./demo
75
+ npm install && npm install --prefix ./playground
74
76
  npm run dev
75
77
  ```
76
78
 
77
- Then open the demo in your browser at <a href="http://localhost:3000" target="_blank">localhost:3000</a>.
79
+ Then open the playground in your browser at <a href="http://localhost:3000" target="_blank">localhost:3000</a>.
78
80
 
79
- To run the demo online, visit:
81
+ To run the playground online, visit:
80
82
 
81
- - https://stackblitz.com/github/davestewart/nuxt-content-assets?file=demo%2Fapp.vue
83
+ - https://stackblitz.com/github/davestewart/nuxt-content-assets?file=playground%2Fapp.vue
82
84
 
83
- To browse the demo folder:
85
+ To browse the playground folder:
84
86
 
85
- - https://github.com/davestewart/nuxt-content-assets/tree/main/demo
87
+ - https://github.com/davestewart/nuxt-content-assets/tree/main/playground
86
88
 
87
89
  ## Setup
88
90
 
@@ -143,7 +145,7 @@ These values can then be passed to components:
143
145
  :image-gallery{:data="images"}
144
146
  ```
145
147
 
146
- See the Demo for [markup](demo/content/advanced/gallery.md) and [component](demo/components/content/ContentGallery.vue) examples.
148
+ See the playground for [markup](playground/content/advanced/gallery.md) and [component](playground/components/content/ContentGallery.vue) examples.
147
149
 
148
150
  ### Live reload
149
151
 
@@ -171,7 +173,7 @@ Keeping this on prevents content jumps as your page loads.
171
173
 
172
174
  #### Prose components
173
175
 
174
- If you use [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can [hook into](demo/components/temp/ProseImg.vue) image size hints via the `$attrs` property:
176
+ If you use [ProseImg](https://content.nuxtjs.org/api/components/prose) components, you can [hook into](playground/components/temp/ProseImg.vue) image size hints via the `$attrs` property:
175
177
 
176
178
  ```vue
177
179
  <template>
@@ -189,7 +191,7 @@ export default {
189
191
 
190
192
  #### Frontmatter
191
193
 
192
- If you pass [frontmatter](demo/content/advanced/gallery.md) to [custom components](demo/components/content/ContentImage.vue) set `imageSize` to `'src'` to encode values in `src`:
194
+ If you pass [frontmatter](playground/content/advanced/gallery.md) to [custom components](playground/components/content/ContentImage.vue) set `imageSize` to `'src'` to encode values in `src`:
193
195
 
194
196
  ```
195
197
  :image-content{:src="image"}
@@ -201,24 +203,32 @@ The component will receive the size information as a query string which you can
201
203
  <img class="image-content" src="/image.jpg?width=640&height=480">
202
204
  ```
203
205
 
204
- See demo component [here](demo/components/content/ContentImage.vue).
205
-
206
- ### Nuxt Image compatibility
206
+ See playground component [here](playground/components/content/ContentImage.vue).
207
207
 
208
- Nuxt Content Assets works with [Nuxt Image](https://image.nuxtjs.org/) with just a little configuration.
208
+ ### Nuxt Image
209
209
 
210
- First, configure Nuxt Image to use Nuxt Content Asset's public folder:
210
+ Nuxt Content Assets works with [Nuxt Image](https://image.nuxtjs.org/) with just a little configuration:
211
211
 
212
212
  ```ts
213
213
  // nuxt.config.ts
214
214
  export default defineNuxtConfig({
215
- image: {
216
- dir: '.nuxt/content-assets/public'
217
- }
215
+ modules: [
216
+ // Nuxt Image should be placed before Nuxt Content Assets
217
+ '@nuxt/image',
218
+ 'nuxt-content-assets',
219
+ '@nuxt/content',
220
+ ],
221
+
222
+ extends: [
223
+ // add Nuxt Content Assets build folder as a Nuxt Layer (since v1.4.0)
224
+ '.nuxt/content-assets',
225
+ ],
218
226
  }
219
227
  ```
220
228
 
221
- Then, create a `ProseImg` component like so:
229
+ > Note that the new Layers setup enables Nuxt Image to load images from both the project's `public` folder and from `content`.
230
+
231
+ To serve all images as Nuxt Image images, create a `ProseImg` component like so:
222
232
 
223
233
  ```vue
224
234
  <!-- components/content/ProseImg.vue -->
@@ -227,9 +237,7 @@ Then, create a `ProseImg` component like so:
227
237
  </template>
228
238
  ```
229
239
 
230
- Any images rendered by Nuxt Content will now use Nuxt Image.
231
-
232
- > For a per-image solution, check the [override](demo/components/content/NuxtImg.ts) in the demo folder.
240
+ See the playground folder for both the [global](playground/components/temp/ProseImg.vue) and a [per image](playground/components/content/NuxtImg.ts) solution.
233
241
 
234
242
 
235
243
  ## Configuration
@@ -264,12 +272,12 @@ You can add one or more image size hints to the generated images:
264
272
 
265
273
  Pick from the following switches:
266
274
 
267
- | Switch | What it does |
268
- | --------- | ------------------------------------------------------------ |
269
- | `'style'` | Adds `style="aspect-ratio:..."` to any `<img>` tag |
270
- | `'attrs'` | Adds `width` and `height` attributes to any `<img>` tag |
275
+ | Switch | What it does |
276
+ |-----------|--------------------------------------------------------------------|
277
+ | `'style'` | Adds `style="aspect-ratio:..."` to any `<img>` tag |
278
+ | `'attrs'` | Adds `width` and `height` attributes to any `<img>` tag |
271
279
  | `'src'` | Adds `?width=...&height=...` to `src` attribute (frontmatter only) |
272
- | `false` | Disable image size hints |
280
+ | `false` | Disable image size hints |
273
281
 
274
282
  Note: if you add *only* `attrs`, include the following CSS in your app:
275
283
 
@@ -318,16 +326,16 @@ In development, file watching propagates asset changes to the public folder, upd
318
326
 
319
327
  Should you wish to develop the project, the scripts are:
320
328
 
321
- Develop the module (running a demo which uses the live module code):
329
+ Develop the module (running the playground which uses the live module code):
322
330
 
323
331
  ```bash
324
332
  # install dependencies
325
333
  npm install
326
334
 
327
- # generate demo type stubs (for the first time)
335
+ # generate playground type stubs (for the first time)
328
336
  npm run dev:prepare
329
337
 
330
- # develop (runs the demo app)
338
+ # develop (runs the playground app)
331
339
  npm run dev
332
340
 
333
341
  # run eslint
@@ -338,27 +346,27 @@ npm run test
338
346
  npm run test:watch
339
347
  ```
340
348
 
341
- Build and check the demo (simulating users' final build choices):
349
+ Build and check the playground (simulating users' final build choices):
342
350
 
343
351
  ```bash
344
- # generate the demo
352
+ # generate the playground
345
353
  npm run dev:generate
346
354
 
347
- # build the demo
355
+ # build the playground
348
356
  npm run dev:build
349
357
 
350
- # serve the built demo
351
- npm run dev:serve
358
+ # serve the generated / built playground
359
+ npm run dev:preview
352
360
  ```
353
361
 
354
362
  Make a new release (so users can install the module):
355
363
 
356
364
  ```bash
357
- # release new version
358
- npm run release
359
-
360
365
  # dry run the release
361
366
  npm run release:dry
367
+
368
+ # release new version
369
+ npm run release
362
370
  ```
363
371
 
364
372
  Make sure to edit changelog and update `package.json` version before releasing!
@@ -375,7 +383,7 @@ This created the module code from the starter template found here:
375
383
 
376
384
  - https://github.com/nuxt/starter/tree/module
377
385
 
378
- Both [Nuxi](https://github.com/nuxt/cli) and the module's dependencies and scripts are updated fairly regularly, so from time to time this module will / does need to be updated to keep in sync. So far, this has meant just updating the dependencies and scripts, which are found in the starter template code mentioned above.
386
+ Both [Nuxi](https://github.com/nuxt/cli) and the module's dependencies and scripts are updated fairly regularly, so from time to time this module may need to be updated to keep in sync. So far, this has meant just updating the dependencies and scripts, which are found in the starter template code mentioned above.
379
387
 
380
388
  <!-- Badges -->
381
389
  [npm-version-src]: https://img.shields.io/npm/v/nuxt-content-assets/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
package/dist/module.json CHANGED
@@ -4,5 +4,5 @@
4
4
  "compatibility": {
5
5
  "nuxt": "^3.0.0"
6
6
  },
7
- "version": "1.3.5"
7
+ "version": "1.4.0"
8
8
  }
package/dist/module.mjs CHANGED
@@ -1,7 +1,5 @@
1
- import * as Fs from 'fs';
2
- import Fs__default from 'fs';
3
- import * as Path from 'crosspath';
4
- import Path__default from 'crosspath';
1
+ import Fs from 'fs';
2
+ import Path from 'crosspath';
5
3
  import { useNuxt, createResolver, defineNuxtModule, addPlugin } from '@nuxt/kit';
6
4
  import { visit, SKIP, CONTINUE } from 'unist-util-visit';
7
5
  import { listen } from 'listhen';
@@ -53,7 +51,7 @@ function isExcluded(path) {
53
51
  return path.split("/").some((segment) => segment.startsWith(".") || segment.startsWith("_"));
54
52
  }
55
53
  function isImage(path) {
56
- const ext = Path__default.extname(path).substring(1);
54
+ const ext = Path.extname(path).substring(1);
57
55
  return extensions.image.includes(ext);
58
56
  }
59
57
  function isArticle(path) {
@@ -155,33 +153,33 @@ function buildQuery(...expr) {
155
153
  }
156
154
 
157
155
  function readFile(path, asJson = false) {
158
- const text = Fs__default.readFileSync(path, { encoding: "utf8" });
156
+ const text = Fs.readFileSync(path, { encoding: "utf8" });
159
157
  return asJson ? JSON.parse(text) : text;
160
158
  }
161
159
  function writeFile(path, data) {
162
160
  const text = typeof data === "object" ? JSON.stringify(data, null, " ") : String(data);
163
- createFolder(Path__default.dirname(path));
164
- Fs__default.writeFileSync(path, text, { encoding: "utf8" });
161
+ createFolder(Path.dirname(path));
162
+ Fs.writeFileSync(path, text, { encoding: "utf8" });
165
163
  }
166
164
  async function writeBlob(path, data) {
167
165
  const buffer = Buffer.from(await data.arrayBuffer());
168
- createFolder(Path__default.dirname(path));
169
- Fs__default.writeFileSync(path, buffer);
166
+ createFolder(Path.dirname(path));
167
+ Fs.writeFileSync(path, buffer);
170
168
  }
171
169
  function copyFile(src, trg) {
172
- createFolder(Path__default.dirname(trg));
173
- Fs__default.copyFileSync(src, trg);
170
+ createFolder(Path.dirname(trg));
171
+ Fs.copyFileSync(src, trg);
174
172
  }
175
173
  function removeFile(src) {
176
- Fs__default.rmSync(src);
174
+ Fs.rmSync(src);
177
175
  }
178
176
  function createFolder(path) {
179
- Fs__default.mkdirSync(path, { recursive: true });
177
+ Fs.mkdirSync(path, { recursive: true });
180
178
  }
181
179
  function removeFolder(path) {
182
- const isDownstream = path.startsWith(Path__default.resolve());
180
+ const isDownstream = path.startsWith(Path.resolve());
183
181
  if (isDownstream) {
184
- Fs__default.rmSync(path, { recursive: true, force: true });
182
+ Fs.rmSync(path, { recursive: true, force: true });
185
183
  }
186
184
  }
187
185
 
@@ -331,13 +329,13 @@ function makeSourceManager(key, source, publicPath, callback) {
331
329
  return toPath(key2).replace(/\w+/, "").replace(source.prefix || "", "");
332
330
  }
333
331
  function getAbsSrc(key2) {
334
- return Path__default.join(source.base, getRelSrc(key2));
332
+ return Path.join(source.base, getRelSrc(key2));
335
333
  }
336
334
  function getRelTrg(key2) {
337
- return Path__default.join(source.prefix || "", toPath(deKey(key2)));
335
+ return Path.join(source.prefix || "", toPath(deKey(key2)));
338
336
  }
339
337
  function getAbsTrg(key2) {
340
- return Path__default.join(publicPath, getRelTrg(key2));
338
+ return Path.join(publicPath, getRelTrg(key2));
341
339
  }
342
340
  function removeItem(key2) {
343
341
  const absTrg = getAbsTrg(key2);
@@ -378,17 +376,22 @@ function makeSourceManager(key, source, publicPath, callback) {
378
376
  return paths;
379
377
  }
380
378
  const storage = makeSourceStorage(source, key);
381
- storage.watch(onWatch);
379
+ void storage.watch(onWatch);
380
+ async function dispose() {
381
+ await storage.unwatch();
382
+ await storage.dispose();
383
+ }
382
384
  return {
383
385
  storage,
384
386
  init,
385
- keys: getKeys
387
+ keys: getKeys,
388
+ dispose
386
389
  };
387
390
  }
388
391
 
389
392
  function makeAssetsManager(publicPath, shouldWatch = true) {
390
393
  const indexKey = "assets.json";
391
- const storage = makeSourceStorage(Path__default.join(publicPath, ".."));
394
+ const storage = makeSourceStorage(Path.join(publicPath, ".."));
392
395
  if (shouldWatch) {
393
396
  void storage.watch(async (event, key) => {
394
397
  if (event === "update" && key === indexKey) {
@@ -405,8 +408,8 @@ function makeAssetsManager(publicPath, shouldWatch = true) {
405
408
  void storage.setItem(indexKey, assets);
406
409
  }, 50);
407
410
  function resolveAsset(content, relAsset, registerContent = false) {
408
- const srcDir = Path__default.dirname(content._file);
409
- const srcAsset = Path__default.join(srcDir, relAsset);
411
+ const srcDir = Path.dirname(content._file);
412
+ const srcAsset = Path.join(srcDir, relAsset);
410
413
  const asset = assets[srcAsset];
411
414
  if (asset && registerContent) {
412
415
  const { _id } = content;
@@ -457,7 +460,7 @@ function makeAssetsManager(publicPath, shouldWatch = true) {
457
460
  };
458
461
  }
459
462
  function getAssetPaths(srcDir, srcAbs) {
460
- const srcRel = Path__default.relative(srcDir, srcAbs);
463
+ const srcRel = Path.relative(srcDir, srcAbs);
461
464
  const srcAttr = "/" + srcRel;
462
465
  return {
463
466
  srcRel,
@@ -527,11 +530,15 @@ const module = defineNuxtModule({
527
530
  const assetsPath = Path.join(buildPath, "content-assets");
528
531
  const publicPath = Path.join(assetsPath, "public");
529
532
  const contentPath = Path.join(buildPath, "content-cache/parsed");
530
- if (options.debug) {
533
+ const isDev = !!nuxt.options.dev;
534
+ const isDebug = !!options.debug;
535
+ if (isDebug) {
531
536
  log("Removing cache folders...");
532
537
  }
533
538
  removeFolder(Path.join(buildPath, "content-cache"));
534
539
  removeFolder(assetsPath);
540
+ createFolder(`${assetsPath}/public`);
541
+ writeFile(`${assetsPath}/nuxt.config.ts`, "export default {}");
535
542
  const { contentExtensions } = options;
536
543
  if (contentExtensions) {
537
544
  nuxt.options.content ||= {};
@@ -557,8 +564,7 @@ const module = defineNuxtModule({
557
564
  };
558
565
  }
559
566
  }
560
- const assets = makeAssetsManager(publicPath, nuxt.options.dev);
561
- nuxt.hooks.hook("close", () => assets.dispose());
567
+ const assets = makeAssetsManager(publicPath, isDev);
562
568
  function onAssetChange(event, absTrg) {
563
569
  let src = "";
564
570
  let width;
@@ -588,35 +594,35 @@ const module = defineNuxtModule({
588
594
  }
589
595
  }
590
596
  addPlugin(resolve("./runtime/sockets/plugin"));
591
- const socket = nuxt.options.dev ? await setupSocketServer("content-assets") : null;
597
+ const socket = isDev ? await setupSocketServer("content-assets") : null;
592
598
  const managers = {};
593
599
  for (const [key, source] of Object.entries(sources)) {
594
- if (options.debug) {
600
+ if (isDebug) {
595
601
  log(`Creating source "${key}"`);
596
602
  }
597
603
  managers[key] = makeSourceManager(key, source, publicPath, onAssetChange);
598
604
  }
599
- nuxt.hook("close", async () => {
600
- for (const key in managers) {
601
- await managers[key].storage.unwatch();
602
- await managers[key].storage.dispose();
603
- }
604
- });
605
605
  nuxt.hook("build:before", async function() {
606
606
  for (const [key, manager] of Object.entries(managers)) {
607
607
  const paths = await manager.init();
608
608
  paths.forEach((path) => assets.setAsset(path));
609
- if (options.debug) {
609
+ if (isDebug) {
610
610
  list(`Copied "${key}" assets`, paths.map((path) => Path.relative(publicPath, path)));
611
611
  }
612
612
  }
613
613
  });
614
+ nuxt.hook("close", async () => {
615
+ await assets.dispose();
616
+ for (const key in managers) {
617
+ await managers[key].dispose();
618
+ }
619
+ });
614
620
  const pluginPath = resolve("./runtime/content/plugin");
615
621
  const makeVar = (name, value) => `export const ${name} = ${JSON.stringify(value)};`;
616
622
  const virtualConfig = [
617
623
  makeVar("publicPath", publicPath),
618
624
  makeVar("imageSizes", imageSizes),
619
- makeVar("debug", options.debug)
625
+ makeVar("debug", isDebug)
620
626
  ].join("\n");
621
627
  nuxt.hook("nitro:config", async (config) => {
622
628
  config.plugins ||= [];
@@ -8,6 +8,7 @@ export interface SourceManager {
8
8
  storage: Storage;
9
9
  init: () => Promise<string[]>;
10
10
  keys: () => Promise<string[]>;
11
+ dispose: () => Promise<void>;
11
12
  }
12
13
  /**
13
14
  * Make a SourceManager instance
@@ -90,10 +90,15 @@ export function makeSourceManager(key, source, publicPath, callback) {
90
90
  return paths;
91
91
  }
92
92
  const storage = makeSourceStorage(source, key);
93
- storage.watch(onWatch);
93
+ void storage.watch(onWatch);
94
+ async function dispose() {
95
+ await storage.unwatch();
96
+ await storage.dispose();
97
+ }
94
98
  return {
95
99
  storage,
96
100
  init,
97
- keys: getKeys
101
+ keys: getKeys,
102
+ dispose
98
103
  };
99
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-content-assets",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "description": "Enable locally-located assets in Nuxt Content",
5
5
  "repository": "davestewart/nuxt-content-assets",
6
6
  "license": "MIT",
@@ -18,13 +18,13 @@
18
18
  "dist"
19
19
  ],
20
20
  "scripts": {
21
- "dev": "nuxi dev demo",
22
- "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare demo",
23
- "dev:generate": "nuxi generate demo",
24
- "dev:build": "nuxi build demo",
25
- "dev:serve": "npx serve demo/dist",
26
- "release": "npm run lint && npm run test && nuxt-module-build build && changelogen --release && npm publish && git push --follow-tags",
21
+ "dev": "nuxi dev playground",
22
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
23
+ "dev:generate": "nuxi generate playground",
24
+ "dev:build": "nuxi build playground",
25
+ "dev:preview": "nuxi preview playground",
27
26
  "release:dry": "npm run lint && npm run test && nuxt-module-build build && npm publish --dry-run",
27
+ "release": "npm run lint && npm run test && nuxt-module-build build && changelogen --release && npm publish && git push --follow-tags",
28
28
  "lint": "eslint .",
29
29
  "test": "vitest run",
30
30
  "test:watch": "vitest watch"
@@ -60,4 +60,4 @@
60
60
  "engines": {
61
61
  "node": ">=16.0.0"
62
62
  }
63
- }
63
+ }