Skip to content

Commit a08029a

Browse files
committed
v5.0.1 Dynamically import puppeteer
1 parent d593ec9 commit a08029a

5 files changed

Lines changed: 69 additions & 9 deletions

File tree

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
# Node metafetch
22

33
[![Build Status](https://github.com/brahma-dev/metafetch/actions/workflows/build.yml/badge.svg)](https://github.com/brahma-dev/metafetch/actions/workflows/build.yml)
4-
[![codecov](https://codecov.io/gh/brahma-dev/metafetch/branch/master/graph/badge.svg)](https://codecov.io/gh/brahma-dev/metafetch)
4+
[![codecov](https://codecov.io/gh/brahma-dev/metafetch/branch/main/graph/badge.svg)](https://codecov.io/gh/brahma-dev/metafetch)
55
[![coveralls](https://coveralls.io/repos/github/brahma-dev/metafetch/badge.svg?branch=main)](https://coveralls.io/github/brahma-dev/metafetch?branch=main)
66
[![Known Vulnerabilities](https://snyk.io/test/npm/metafetch/badge.svg?style=flat)](https://snyk.io/test/npm/metafetch)
77
[![NPM version](https://img.shields.io/npm/v/metafetch.svg?style=flat)](https://www.npmjs.org/package/metafetch)
88

99
**Metafetch** is a library to fetch and parse metadata from a web page. It can extract standard meta tags, Open Graph data, JSON-LD, favicons, and feeds, and even render client-side JavaScript to get data from Single-Page Applications (SPAs).
1010

11+
## Table of Contents
12+
13+
- [Key Features](#key-features)
14+
- [Installation](#installation)
15+
- [Usage](#usage)
16+
- [Basic Example](#basic-example)
17+
- [Advanced Example (Rendering SPAs & Retries)](#advanced-example-rendering-spas--retries)
18+
- [API](#api)
19+
- [`metafetch.fetch(url, [options])`](#metafetchfetchurl-options)
20+
- [Available Flags](#available-flags)
21+
- [Instance Management](#instance-management)
22+
- [Response Data](#response-data)
23+
- [License](#license)
24+
1125
## Key Features
1226

1327
* **Comprehensive Metadata:** Extracts title, description, URL, site name, images, links, and more.
@@ -25,9 +39,10 @@
2539
Use NPM to install:
2640

2741
```bash
28-
npm install metafetch puppeteer
42+
npm install metafetch
2943
```
30-
*Note: `puppeteer` is a peer dependency and must be installed separately if you want to use the client-side rendering feature.*
44+
45+
*Note: **`puppeteer`** is a peer dependency and must be installed separately (`npm install puppeteer`) if you want to use the SPA / client-side rendering feature.*
3146

3247
## Usage
3348

@@ -59,6 +74,7 @@ This will output a representative object like this:
5974
type: 'article',
6075
url: 'https://example.com/article-path',
6176
originalURL: 'https://example.com',
77+
ampURL: 'https://example.com/article-path/amp',
6278
siteName: 'Example News',
6379
charset: 'utf-8',
6480
image: 'https://example.com/images/featured-image.png',

package-lock.json

Lines changed: 10 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "metafetch",
33
"description": "Metafetch fetches a given URL's title, description, images, links etc.",
4-
"version": "5.0.0",
4+
"version": "5.0.1",
55
"homepage": "https://github.com/brahma-dev/metafetch",
66
"repository": {
77
"type": "git",
@@ -25,7 +25,12 @@
2525
"linkedom": "^0.18.11"
2626
},
2727
"peerDependencies": {
28-
"puppeteer": "^24.16.1"
28+
"puppeteer": ">=22.0.0 <25.0.0"
29+
},
30+
"peerDependenciesMeta": {
31+
"puppeteer": {
32+
"optional": true
33+
}
2934
},
3035
"devDependencies": {
3136
"@istanbuljs/nyc-config-typescript": "^1.0.2",

src/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { parseHTML } from 'linkedom';
22
import type { Document } from 'linkedom';
3-
import puppeteer from 'puppeteer';
43

54
/**
65
* The shape of the response object returned by Metafetch.
@@ -80,6 +79,14 @@ export class Metafetch {
8079
return this.#userAgent;
8180
}
8281

82+
/**
83+
* Wrapper for dynamic import of puppeteer to improve testability.
84+
* @private
85+
*/
86+
private async _getPuppeteer() {
87+
return import('puppeteer');
88+
}
89+
8390
/**
8491
* Fetches and parses metadata from a given URL.
8592
* @param url The URL to fetch.
@@ -112,6 +119,15 @@ export class Metafetch {
112119
let encoding: string;
113120

114121
if (options.render) {
122+
let puppeteer;
123+
try {
124+
const puppeteerModule = await this._getPuppeteer();
125+
puppeteer = puppeteerModule.default;
126+
} catch (err) {
127+
throw new Error(
128+
'The "render" option requires the "puppeteer" package. Please install it (`npm install puppeteer`) and try again.'
129+
);
130+
}
115131
const browser = await puppeteer.launch({
116132
headless: true, args: [
117133
'--no-sandbox',

test/test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('Metafetch: Optimized Tests', () => {
3737
res.setHeader('Content-Type', 'text/html; charset=iso-8859-1').end('<body></body>');
3838
return;
3939
case '/charset-meta':
40-
res.setHeader('Content-Type', 'text/html');
40+
res.setHeader('Content-Type', 'text/html');
4141
body = '<head><meta charset="windows-1252"></head>';
4242
break;
4343
case '/base-tag':
@@ -470,6 +470,21 @@ describe('Metafetch: Optimized Tests', () => {
470470
expect(err.message).to.equal("Received an empty response body.");
471471
}
472472
});
473+
474+
it('should throw a helpful error when puppeteer fails to import', async () => {
475+
const newInstance = new Metafetch();
476+
// Stub the private method to simulate an import failure
477+
const importStub = sinon.stub(newInstance as any, '_getPuppeteer').rejects(new Error('Simulated import failure'));
478+
479+
try {
480+
await newInstance.fetch(`${BASE_URL}/page`, { render: true });
481+
throw new Error("Test failed: Metafetch should have thrown an error.");
482+
} catch (err: any) {
483+
expect(err.message).to.equal('The "render" option requires the "puppeteer" package. Please install it (`npm install puppeteer`) and try again.');
484+
} finally {
485+
importStub.restore();
486+
}
487+
});
473488
});
474489

475490
describe('Request Retries', () => {

0 commit comments

Comments
 (0)