nest-puppeteer
Version:
Puppeteer (Headless Chrome) provider for Nest.js
212 lines (161 loc) • 6.36 kB
Markdown
# nest-puppeteer [](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 /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 '/common';
import { PuppeteerModule } from 'nest-puppeteer';
({
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 '/common';
import { InjectBrowser } from 'nest-puppeteer';
import { Cat } from './interfaces/cat';
()
export class CatsRepository {
constructor(() 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 '/common';
import { PuppeteerModule } from 'nest-puppeteer';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
({
imports: [PuppeteerModule.forFeature()],
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
```
```typescript
import type { BrowserContext } from 'puppeteer';
import { Injectable } from '/common';
import { InjectContext } from 'nest-puppeteer';
import { Cat } from './interfaces/cat';
()
export class CatsRepository {
constructor(
() 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 '/common';
import { InjectPage } from 'nest-puppeteer';
import type { Page } from 'puppeteer';
()
export class CrawlerService {
constructor(() 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 '/common'
import { PuppeteerModule } from 'nest-puppeteer'
import { ConfigService } from '../config/config.service'
({
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 '/common';
import {
PuppeteerModule,
PuppeteerOptionsFactory,
PuppeteerModuleOptions,
} from 'nest-puppeteer';
()
export class PuppeteerConfigService implements PuppeteerOptionsFactory {
private readonly launchOptions = { pipe: true };
private readonly dbName = 'BestAppEver';
createMongoOptions(): PuppeteerModuleOptions {
return {
launchOptions: this.launchOptions,
instanceName: this.instanceName,
};
}
}
({
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 '/common'
import { PuppeteerModule } from 'nest-puppeteer'
import { ConfigModule, ConfigService } from '../config/config.service'
({
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](tino.io)
## License
`nest-puppeteer` is [MIT licensed](LICENSE).