nuxt-og-image 0.4.7 → 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
@@ -18,7 +18,7 @@ Generate dynamic social share images for you Nuxt v3 app.
18
18
  <tbody>
19
19
  <td align="center">
20
20
  <img width="800" height="0" /><br>
21
- <i>Status:</i> 🤫 Early Access - Active Development 🤫</b> <br>
21
+ <i>Status:</i> Early Access</b> <br>
22
22
  <sup> Please report any issues 🐛</sup><br>
23
23
  <sub>Made possible by my <a href="https://github.com/sponsors/harlan-zw">Sponsor Program 💖</a><br> Follow me <a href="https://twitter.com/harlan_zw">@harlan_zw</a> 🐦 • Join <a href="https://discord.gg/275MBUBvgP">Discord</a> for help</sub><br>
24
24
  <img width="800" height="0" />
@@ -29,32 +29,39 @@ Generate dynamic social share images for you Nuxt v3 app.
29
29
 
30
30
  ## Features
31
31
 
32
- - 🧙 Generate images for your entire site in minutes with minimal config
33
- - 🎨 Build your own template with Vue (powered by Nuxt Islands)
34
- - 📸 OR just generates page screenshots
35
- - 📦 Composable and component API
32
+ - 🧙 Pre-render `og:image`'s for your entire site in minutes with minimal config
33
+ - 🎨 Using a Vue component (powered by Nuxt Islands)
34
+ - 📸 OR just generate screenshots
35
+ - 📦 Choose your API: Composition or components
36
+
37
+ ⚠️ SSR runtime rendering is experimental.
36
38
 
37
39
  ## Install
38
40
 
39
- ⚠️ This module is still in development. Please get in touch with me over [Twitter](https://twitter.com/harlan_zw) or Discord if you are going to attempt to use this.
41
+ ⚠️ This module is in early access. Please report any issues you find.
40
42
 
41
43
  ```bash
44
+ # Install module
42
45
  npm install --save-dev nuxt-og-image
43
46
  # Using yarn
44
47
  yarn add --dev nuxt-og-image
45
48
  ```
46
49
 
47
- ### Chromium Dependency
50
+ If you don't have a chromium binary installed on your system, run `npx playwright install`.
48
51
 
49
- By default, this module does not install chromium binaries for you, instead relying on locally
50
- installed chrome.
52
+ ### CI Build
51
53
 
52
- If you want to use this module in a CI or SSR environment, you will need the binaries.
54
+ If you are using this module in a CI context and the images aren't being generated,
55
+ you should replace your build script with the following:
53
56
 
54
- You can either use `puppeteer` or `chrome-aws-lambda`.
57
+ _package.json_
55
58
 
56
- ```bash
57
- npm install --save-dev puppeteer # or chrome-aws-lambda
59
+ ```json
60
+ {
61
+ "scripts": {
62
+ "build": "npx playwright install && nuxt build"
63
+ }
64
+ }
58
65
  ```
59
66
 
60
67
  ## Setup
@@ -108,25 +115,6 @@ export default defineNuxtConfig({
108
115
  })
109
116
  ```
110
117
 
111
- ### Recommended: Enable Nuxt Islands
112
-
113
- To be able to preview the image in development and generate template images, you'll need
114
- to enable Nuxt Islands.
115
-
116
- If you're using Nuxt 3.0.0, you will need to switch to the [edge-release channel](https://nuxt.com/docs/guide/going-further/edge-channel#edge-release-channel).
117
-
118
- Once that's done, you can enable the flag for islands.
119
-
120
- _nuxt.config.ts_
121
-
122
- ```ts
123
- export default defineNuxtConfig({
124
- experimental: {
125
- componentIslands: true
126
- },
127
- })
128
- ```
129
-
130
118
  ## Generating Screenshots
131
119
 
132
120
  _Your page / app.vue / layout_
@@ -156,6 +144,7 @@ _Your page / app.vue / layout_
156
144
  // Choose either Composition API
157
145
  defineOgImage({
158
146
  component: 'OgImageTemplate', // Nuxt Island component
147
+ alt: 'My awesome image', // alt text for image
159
148
  // pass in any custom props
160
149
  myCustomTitle: 'My Title'
161
150
  })
@@ -168,6 +157,25 @@ defineOgImage({
168
157
  </template>
169
158
  ```
170
159
 
160
+ ### Requirements
161
+
162
+ To be able to preview the image in development and generate template images, you'll need
163
+ to enable Nuxt Islands.
164
+
165
+ If you're using Nuxt 3.0.0, you will need to switch to the [edge-release channel](https://nuxt.com/docs/guide/going-further/edge-channel#edge-release-channel).
166
+
167
+ Once that's done, you can enable the flag for islands.
168
+
169
+ _nuxt.config.ts_
170
+
171
+ ```ts
172
+ export default defineNuxtConfig({
173
+ experimental: {
174
+ componentIslands: true
175
+ },
176
+ })
177
+ ```
178
+
171
179
  ### Creating your own template
172
180
 
173
181
  Create a new component with `.island.vue` as the suffix, such as `components/Banner.island.vue`.
@@ -250,6 +258,9 @@ The host of your site. This is required to generate the absolute path of the og:
250
258
  Allows you to generate images at runtime in production. This uses a headless browser to generate images
251
259
  and may have deployment issues.
252
260
 
261
+ ⚠️ This is experimental and will likely not work in all environments.
262
+
263
+
253
264
  ## Examples
254
265
 
255
266
  - [Unhead Docs](https://github.com/unjs/unhead/tree/main/docs)
package/dist/module.d.ts CHANGED
@@ -36,9 +36,9 @@ interface ModuleOptions extends ScreenshotOptions {
36
36
  */
37
37
  host: string;
38
38
  /**
39
- * Should images be allowed to generated at runtime.
39
+ * Are we edge-side rendering images.
40
40
  */
41
- runtimeImages: boolean;
41
+ edgeSideRender: boolean;
42
42
  }
43
43
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
44
44
 
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "bridge": false
6
6
  },
7
7
  "configKey": "ogImage",
8
- "version": "0.4.7"
8
+ "version": "0.5.2"
9
9
  }
package/dist/module.mjs CHANGED
@@ -11,29 +11,14 @@ import { join } from 'pathe';
11
11
 
12
12
  async function createBrowser() {
13
13
  try {
14
- const playwrightCore = await import('playwright-core');
15
- process.env.AWS_LAMBDA_FUNCTION_NAME = process.env.AWS_LAMBDA_FUNCTION_NAME || "RUNTIME_HACK";
16
- const awsChrome = await import(String("chrome-aws-lambda"));
17
- return await playwrightCore.chromium.launch({
18
- args: awsChrome.args,
19
- executablePath: await awsChrome.executablePath,
20
- headless: awsChrome.headless
21
- });
22
- } catch (e) {
23
- if (!process.dev)
24
- console.log("[nuxt-og-image] Skipping chrome-aws-lambda", e);
25
- }
26
- try {
27
- const playwrightCore = await import('playwright-core');
28
- const { Launcher } = await import('chrome-launcher');
14
+ const playwrightCore = await import(String("playwright-core"));
15
+ const { Launcher } = await import(String("chrome-launcher"));
29
16
  const chromePath = Launcher.getFirstInstallation();
30
17
  return await playwrightCore.chromium.launch({
31
18
  headless: true,
32
19
  executablePath: chromePath
33
20
  });
34
21
  } catch (e) {
35
- if (!process.dev)
36
- console.log("[nuxt-og-image] Skipping chrome-launcher", e);
37
22
  }
38
23
  try {
39
24
  const playwright = await import(String("playwright"));
@@ -41,14 +26,9 @@ async function createBrowser() {
41
26
  headless: true
42
27
  });
43
28
  } catch (e) {
44
- if (!process.dev)
45
- console.log("[nuxt-og-image] Playwright failed", e);
46
- throw new Error(`
47
- Missing chromium binary. You need either 'playwright' or 'chrome-aws-lambda'.
48
- Please run 'yarn add --dev playwright' or 'npm install --save-dev playwright'
49
- `);
50
29
  }
51
30
  }
31
+
52
32
  async function screenshot(browser, url, options) {
53
33
  const page = await browser.newPage({
54
34
  colorScheme: options.colorScheme
@@ -101,12 +81,13 @@ const module = defineNuxtModule({
101
81
  height: 630,
102
82
  defaultIslandComponent: "OgImageTemplate",
103
83
  outputDir: "_og-images",
104
- runtimeImages: nuxt.options.dev
84
+ edgeSideRender: nuxt.options.dev || (process.env.NITRO_PRESET || "").includes("edge")
105
85
  };
106
86
  },
107
87
  async setup(config, nuxt) {
108
88
  const { resolve } = createResolver(import.meta.url);
109
89
  nuxt.options.experimental.componentIslands = true;
90
+ const isEdge = (process.env.NITRO_PRESET || "").includes("edge");
110
91
  addTemplate({
111
92
  filename: "nuxt-og-image.d.ts",
112
93
  getContents: () => {
@@ -126,7 +107,7 @@ declare module 'nitropack' {
126
107
  addServerHandler({
127
108
  handler: resolve("./runtime/nitro/html")
128
109
  });
129
- if (config.runtimeImages) {
110
+ if (config.edgeSideRender) {
130
111
  addServerHandler({
131
112
  handler: resolve("./runtime/nitro/image")
132
113
  });
@@ -164,6 +145,11 @@ declare module 'nitropack' {
164
145
  inline: [runtimeDir]
165
146
  });
166
147
  nitroConfig.virtual["#nuxt-og-image/constants"] = constScript;
148
+ nitroConfig.virtual["#nuxt-og-image/browser"] = `export { createBrowser } from '${runtimeDir}/browsers/${isEdge ? "lambda" : "default"}'`;
149
+ if (isEdge) {
150
+ nitroConfig.alias.puppeteer = "unenv/runtime/mock/proxy-cjs";
151
+ nitroConfig.alias.ws = "unenv/runtime/mock/proxy-cjs";
152
+ }
167
153
  });
168
154
  nuxt.hooks.hook("nitro:init", async (nitro) => {
169
155
  let entries = [];
@@ -1,5 +1,4 @@
1
1
  /// <reference types="node" />
2
2
  import type { Browser } from 'playwright-core';
3
3
  import type { ScreenshotOptions } from '../types';
4
- export declare function createBrowser(): Promise<any>;
5
4
  export declare function screenshot(browser: Browser, url: string, options: ScreenshotOptions): Promise<Buffer>;
@@ -0,0 +1,22 @@
1
+ export async function screenshot(browser, url, options) {
2
+ const page = await browser.newPage({
3
+ colorScheme: options.colorScheme
4
+ });
5
+ await page.setViewportSize({
6
+ width: options.width,
7
+ height: options.height
8
+ });
9
+ await page.goto(url, {
10
+ timeout: 1e4,
11
+ waitUntil: "networkidle"
12
+ });
13
+ if (options.mask) {
14
+ await page.evaluate((mask) => {
15
+ for (const el of document.querySelectorAll(mask))
16
+ el.style.display = "none";
17
+ }, options.mask);
18
+ }
19
+ if (options.selector)
20
+ await page.locator(options.selector).screenshot();
21
+ return await page.screenshot();
22
+ }
@@ -0,0 +1 @@
1
+ export declare function createBrowser(): Promise<any>;
@@ -0,0 +1,19 @@
1
+ export async function createBrowser() {
2
+ try {
3
+ const playwrightCore = await import(String("playwright-core"));
4
+ const { Launcher } = await import(String("chrome-launcher"));
5
+ const chromePath = Launcher.getFirstInstallation();
6
+ return await playwrightCore.chromium.launch({
7
+ headless: true,
8
+ executablePath: chromePath
9
+ });
10
+ } catch (e) {
11
+ }
12
+ try {
13
+ const playwright = await import(String("playwright"));
14
+ return await playwright.chromium.launch({
15
+ headless: true
16
+ });
17
+ } catch (e) {
18
+ }
19
+ }
@@ -0,0 +1 @@
1
+ export declare function createBrowser(): Promise<import("puppeteer-core").Browser>;
@@ -0,0 +1,9 @@
1
+ import edgeChromium from "chrome-aws-lambda";
2
+ import puppeteer from "puppeteer-core";
3
+ export async function createBrowser() {
4
+ return puppeteer.launch({
5
+ args: edgeChromium.args,
6
+ executablePath: await edgeChromium.executablePath,
7
+ headless: true
8
+ });
9
+ }
@@ -3,6 +3,7 @@ export interface OgImagePayload {
3
3
  title?: string;
4
4
  description?: string;
5
5
  component?: string;
6
+ alt?: string;
6
7
  [key: string]: any;
7
8
  }
8
9
  export declare function defineOgImageScreenshot(): void;
@@ -10,10 +10,18 @@ export function defineOgImage(options = {}) {
10
10
  const route = router?.currentRoute?.value?.path || "";
11
11
  useServerHead({
12
12
  meta: [
13
+ {
14
+ property: "twitter:card",
15
+ content: "summary_large_image"
16
+ },
13
17
  {
14
18
  property: "og:image",
15
19
  content: () => options.runtime ? `${route}/${DefaultRuntimeImageSuffix}` : MetaOgImageContentPlaceholder
16
- }
20
+ },
21
+ options.alt ? {
22
+ property: "og:image:alt",
23
+ content: options.alt
24
+ } : {}
17
25
  ],
18
26
  link: options.component ? [
19
27
  {
@@ -1,3 +1,3 @@
1
1
  /// <reference types="node" />
2
- declare const _default: import("h3").EventHandler<Buffer | undefined>;
2
+ declare const _default: import("h3").EventHandler<Buffer | import("h3").H3Error | undefined>;
3
3
  export default _default;
@@ -1,12 +1,15 @@
1
- import { defineEventHandler, getRequestHeader, setHeader } from "h3";
2
- import { createBrowser, screenshot } from "../browserService.mjs";
1
+ import { createError, defineEventHandler, getRequestHeader, setHeader } from "h3";
2
+ import { screenshot } from "../browserUtil.mjs";
3
3
  import { DefaultRuntimeImageSuffix, HtmlRendererRoute } from "#nuxt-og-image/constants";
4
+ import { createBrowser } from "#nuxt-og-image/browser";
4
5
  export default defineEventHandler(async (e) => {
5
6
  if (!e.path?.endsWith(DefaultRuntimeImageSuffix))
6
7
  return;
7
8
  const path = e.path.replace(DefaultRuntimeImageSuffix, HtmlRendererRoute);
8
9
  const host = getRequestHeader(e, "host") || "localhost:3000";
9
10
  const browser = await createBrowser();
11
+ if (!browser)
12
+ return createError("Could not create browser");
10
13
  setHeader(e, "Content-Type", "image/png");
11
14
  return await screenshot(browser, `http${host.startsWith("localhost") ? "" : "s"}://${host}/${path}`, {
12
15
  width: 1200,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-og-image",
3
3
  "type": "module",
4
- "version": "0.4.7",
4
+ "version": "0.5.2",
5
5
  "packageManager": "pnpm@7.8.0",
6
6
  "license": "MIT",
7
7
  "funding": "https://github.com/sponsors/harlan-zw",
@@ -34,7 +34,6 @@
34
34
  "fast-glob": "^3.2.12",
35
35
  "ohash": "^1.0.0",
36
36
  "pathe": "^1.0.0",
37
- "playwright-core": "^1.28.1",
38
37
  "radix3": "^1.0.0",
39
38
  "ufo": "^1.0.1"
40
39
  },
@@ -47,6 +46,7 @@
47
46
  "bumpp": "^8.2.1",
48
47
  "eslint": "8.29.0",
49
48
  "nuxt": "npm:nuxt3@latest",
49
+ "playwright-core": "^1.28.1",
50
50
  "puppeteer": "^19.4.0",
51
51
  "vitest": "^0.25.5"
52
52
  },
@@ -1,62 +0,0 @@
1
- export async function createBrowser() {
2
- try {
3
- const playwrightCore = await import("playwright-core");
4
- process.env.AWS_LAMBDA_FUNCTION_NAME = process.env.AWS_LAMBDA_FUNCTION_NAME || "RUNTIME_HACK";
5
- const awsChrome = await import(String("chrome-aws-lambda"));
6
- return await playwrightCore.chromium.launch({
7
- args: awsChrome.args,
8
- executablePath: await awsChrome.executablePath,
9
- headless: awsChrome.headless
10
- });
11
- } catch (e) {
12
- if (!process.dev)
13
- console.log("[nuxt-og-image] Skipping chrome-aws-lambda", e);
14
- }
15
- try {
16
- const playwrightCore = await import("playwright-core");
17
- const { Launcher } = await import("chrome-launcher");
18
- const chromePath = Launcher.getFirstInstallation();
19
- return await playwrightCore.chromium.launch({
20
- headless: true,
21
- executablePath: chromePath
22
- });
23
- } catch (e) {
24
- if (!process.dev)
25
- console.log("[nuxt-og-image] Skipping chrome-launcher", e);
26
- }
27
- try {
28
- const playwright = await import(String("playwright"));
29
- return await playwright.chromium.launch({
30
- headless: true
31
- });
32
- } catch (e) {
33
- if (!process.dev)
34
- console.log("[nuxt-og-image] Playwright failed", e);
35
- throw new Error(`
36
- Missing chromium binary. You need either 'playwright' or 'chrome-aws-lambda'.
37
- Please run 'yarn add --dev playwright' or 'npm install --save-dev playwright'
38
- `);
39
- }
40
- }
41
- export async function screenshot(browser, url, options) {
42
- const page = await browser.newPage({
43
- colorScheme: options.colorScheme
44
- });
45
- await page.setViewportSize({
46
- width: options.width,
47
- height: options.height
48
- });
49
- await page.goto(url, {
50
- timeout: 1e4,
51
- waitUntil: "networkidle"
52
- });
53
- if (options.mask) {
54
- await page.evaluate((mask) => {
55
- for (const el of document.querySelectorAll(mask))
56
- el.style.display = "none";
57
- }, options.mask);
58
- }
59
- if (options.selector)
60
- await page.locator(options.selector).screenshot();
61
- return await page.screenshot();
62
- }