Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tinovyatkin/nest-puppeteer

Puppeteer (Headless Chrome) provider for Nest.js
https://github.com/tinovyatkin/nest-puppeteer

headless-chrome nestjs nestjs-library puppeteer

Last synced: 5 days ago
JSON representation

Puppeteer (Headless Chrome) provider for Nest.js

Awesome Lists containing this project

README

        

# nest-puppeteer [![codecov](https://codecov.io/gh/tinovyatkin/nest-puppeteer/branch/master/graph/badge.svg)](https://codecov.io/gh/tinovyatkin/nest-puppeteer)

## Description

This is a Puppeteer module for [NestJS](https://nestjs.com/), making it easy to inject the [Puppeteer](https://github.com/puppeteer/puppeteer) into your project. It's modeled after the official modules, allowing for asynchronous configuration and such.

## Installation

In your existing NestJS-based project:

```sh
npm install nest-puppeteer puppeteer
npm install -D @types/puppeteer
```

## Usage

Overall, it works very similarly to any injectable module described in the NestJS documentation. You may want to refer to those docs as well -- and maybe the [dependency injection](https://docs.nestjs.com/fundamentals/custom-providers) docs too if you're still trying to wrap your head around the NestJS implementation of it.

### Simple example

In the simplest case, you can explicitly specify options you'd normally provide to your `puppeteer.launch` or the instance name using `PuppeteerModule.forRoot()`:

```typescript
import { Module } from '@nestjs/common';
import { PuppeteerModule } from 'nest-puppeteer';

@Module({
imports: [
PuppeteerModule.forRoot(
{ pipe: true }, // optional, any Puppeteer launch options here or leave empty for good defaults */,
'BrowserInstanceName', // optional, can be useful for using Chrome and Firefox in the same project
),
],
})
export class CatsModule {}
```

To inject the Puppeteer `Browser` object:

```typescript
import type { Browser } from 'puppeteer';
import { Injectable } from '@nestjs/common';
import { InjectBrowser } from 'nest-puppeteer';
import { Cat } from './interfaces/cat';

@Injectable()
export class CatsRepository {
constructor(@InjectBrowser() private readonly browser: Browser) {}

async create(cat: Cat) {
const version = await this.browser.version();
return { version };
}
}
```

To inject a new incognito `BrowserContext` object:

```typescript
import { Module } from '@nestjs/common';
import { PuppeteerModule } from 'nest-puppeteer';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
imports: [PuppeteerModule.forFeature()],
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
```

```typescript
import type { BrowserContext } from 'puppeteer';
import { Injectable } from '@nestjs/common';
import { InjectContext } from 'nest-puppeteer';
import { Cat } from './interfaces/cat';

@Injectable()
export class CatsRepository {
constructor(
@InjectContext() private readonly browserContext: BrowserContext,
) {}

async create(cat: Cat) {
const page = await this.browserContext.newPage();
await page.goto('https://test.com/');
return await page.content();
}
}
```

Inject `Page` object:

```typescript
import { Injectable } from '@nestjs/common';
import { InjectPage } from 'nest-puppeteer';
import type { Page } from 'puppeteer';

@Injectable()
export class CrawlerService {
constructor(@InjectPage() private readonly page: Page) {}

async crawl(url: string) {
await this.page.goto(url, { waitUntil: 'networkidle2' });
const content = await this.page.content();
return { content };
}
}
```

### Asynchronous configuration

If you want to pass in Puppeteer configuration options from a ConfigService or other provider, you'll need to perform the Puppeteer module configuration asynchronously, using `PuppeteerModule.forRootAsync()`. There are several different ways of doing this.

#### Use a factory function

The first is to specify a factory function that populates the options:

```typescript
import { Module } from '@nestjs/common'
import { PuppeteerModule } from 'nest-puppeteer'
import { ConfigService } from '../config/config.service'

@Module({
imports: [PuppeteerModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => {
launchOptions: config.chromeLaunchOptions,
},
inject: [ConfigService]
})]
})
export class CatsModule {}
```

#### Use a class

Alternatively, you can write a class that implements the `PuppeteerOptionsFactory` interface and use that to create the options:

```typescript
import { Module } from '@nestjs/common';
import {
PuppeteerModule,
PuppeteerOptionsFactory,
PuppeteerModuleOptions,
} from 'nest-puppeteer';

@Injectable()
export class PuppeteerConfigService implements PuppeteerOptionsFactory {
private readonly launchOptions = { pipe: true };
private readonly dbName = 'BestAppEver';

createMongoOptions(): PuppeteerModuleOptions {
return {
launchOptions: this.launchOptions,
instanceName: this.instanceName,
};
}
}

@Module({
imports: [
PuppeteerModule.forRootAsync({
useClass: PuppeteerConfigService,
}),
],
})
export class CatsModule {}
```

Just be aware that the `useClass` option will instantiate your class inside the PuppeteerModule, which may not be what you want.

#### Use existing

If you wish to instead import your PuppeteerConfigService class from a different module, the `useExisting` option will allow you to do that.

```typescript
import { Module } from '@nestjs/common'
import { PuppeteerModule } from 'nest-puppeteer'
import { ConfigModule, ConfigService } from '../config/config.service'

@Module({
imports: [PuppeteerModule.forRootAsync({
imports: [ConfigModule]
useExisting: ConfigService
})]
})
export class CatsModule {}
```

In this example, we're assuming that `ConfigService` implements the `PuppeteerOptionsFactory` interface and can be found in the ConfigModule.

#### Use module globally

When you want to use `PuppeteerModule` in other modules, you'll need to import it (as is standard with any Nest module). Alternatively, declare it as a [global module](https://docs.nestjs.com/modules#global-modules) by setting the options object's `isGlobal` property to `true`, as shown below. In that case, you will not need to import `PuppeteerModule` in other modules once it's been loaded in the root module (e.g., `AppModule`).

```typescript
PuppeteerModule.forRoot({
isGlobal: true,
});
```

## Stay in touch

- Author - [Konstantin Vyatkin]([email protected])

## License

`nest-puppeteer` is [MIT licensed](LICENSE).