From aa2ee223ae1964432f3ce4641acf8c621c07fe06 Mon Sep 17 00:00:00 2001 From: Filip Weiss Date: Sat, 23 May 2026 11:40:07 +0200 Subject: [PATCH] feat: re-export browser creators, add CLI wrapper, and fix docs - Re-export 'chromium', 'firefox', and 'webkit' from 'playwright-core' in the main index. - Add an 'effect-playwright' CLI wrapper that forwards commands directly to 'playwright-core' CLI. - Correct 'page.title' examples to properly treat it as an effect in 'README.md'. - Clean up imports and documentation examples to import browser engines directly from 'effect-playwright'. --- AGENTS.md | 5 ++--- README.md | 38 ++++++++++++++++++++------------- bin/cli.mjs | 10 +++++++++ package.json | 9 ++++++-- src/experimental/environment.ts | 4 ++-- src/index.ts | 4 ++-- src/playwright.ts | 21 +++++++++--------- 7 files changed, 57 insertions(+), 34 deletions(-) create mode 100755 bin/cli.mjs diff --git a/AGENTS.md b/AGENTS.md index 767ca11..6013c95 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,9 +49,8 @@ Use `pnpm` for all package management tasks. ```typescript import { assert, layer } from "@effect/vitest"; import { Effect } from "effect"; - import { chromium } from "playwright-core"; - import { PlaywrightBrowser } from "./browser"; - import { PlaywrightEnvironment } from "./experimental"; + import { PlaywrightBrowser, chromium } from "effect-playwright"; + import { PlaywrightEnvironment } from "effect-playwright/experimental"; // Use the PlaywrightEnvironment layer layer(PlaywrightEnvironment.layer(chromium))("Suite Name", (it) => { diff --git a/README.md b/README.md index bc5290a..eefab1e 100644 --- a/README.md +++ b/README.md @@ -13,23 +13,17 @@ A Playwright wrapper for the Effect ecosystem. This library provides a set of se ## Installation ```bash -pnpm add effect-playwright playwright-core +pnpm add effect-playwright +pnpm effect-playwright install chromium ``` -or - -```bash -npm install effect-playwright playwright-core -``` - -You can also install `playwright` instead of `playwright-core` if you want the post-build auto install of the browsers. +Browser installation is not required if connecting to an existing browser via CDP or using a local browser. ## Quick Start ```ts -import { Playwright } from "effect-playwright"; +import { Playwright, chromium } from "effect-playwright"; import { Effect } from "effect"; -import { chromium } from "playwright-core"; const program = Effect.gen(function* () { const playwright = yield* Playwright; @@ -37,7 +31,8 @@ const program = Effect.gen(function* () { const page = yield* browser.newPage(); yield* page.goto("https://example.com"); - console.log(`Page title: ${page.title()}`); + const title = yield* page.title; + yield* Effect.log(`Page title: ${title}`); }).pipe(Effect.scoped, Effect.provide(Playwright.layer)); await Effect.runPromise(program); @@ -92,10 +87,9 @@ The `PlaywrightEnvironment` simplifies setup by allowing you to configure the br ### Usage ```ts -import { PlaywrightBrowser } from "effect-playwright"; +import { PlaywrightBrowser, chromium } from "effect-playwright"; import { PlaywrightEnvironment } from "effect-playwright/experimental"; import { Effect } from "effect"; -import { chromium } from "playwright-core"; const liveLayer = PlaywrightEnvironment.layer(chromium, { headless: false /** any other launch options */, @@ -164,9 +158,8 @@ const program = Effect.gen(function* () { If you need to access functionality from the underlying Playwright objects that isn't directly exposed, you can use the `use` method available on most services/objects (browsers, pages, locators). ```ts -import { Playwright } from "effect-playwright"; +import { Playwright, chromium } from "effect-playwright"; import { Effect } from "effect"; -import { chromium } from "playwright-core"; const program = Effect.gen(function* () { const playwright = yield* Playwright; @@ -183,3 +176,18 @@ const program = Effect.gen(function* () { All methods return effects that can fail with a `PlaywrightError`. This error wraps the original error from Playwright. Note that Playwright does not support interruption, so `Effect.timeout` or similar code does not behave like you might expect. Playwright provides its own `timeout` option for almost every method. + +## CLI Wrapper + +`effect-playwright` includes a lightweight command-line wrapper that forwards all commands directly to the underlying `playwright-core` CLI. You can use it to install browsers, generate code, or inspect traces: + +```bash +# Install browsers +pnpm effect-playwright install chromium + +# Code generation +pnpm effect-playwright codegen https://example.com + +# Open inspector / trace viewer +pnpm effect-playwright show-trace trace.zip +``` diff --git a/bin/cli.mjs b/bin/cli.mjs new file mode 100755 index 0000000..134a878 --- /dev/null +++ b/bin/cli.mjs @@ -0,0 +1,10 @@ +#!/usr/bin/env node +import { createRequire } from "node:module"; +import path from "node:path"; + +const require = createRequire(import.meta.url); +const cliPath = path.join( + path.dirname(require.resolve("playwright-core/package.json")), + "cli.js", +); +require(cliPath); diff --git a/package.json b/package.json index bfdb78f..d98edef 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,12 @@ "./experimental": "./dist/experimental/index.mjs", "./package.json": "./package.json" }, + "bin": { + "effect-playwright": "./bin/cli.mjs" + }, "files": [ - "dist" + "dist", + "bin" ], "scripts": { "build": "tsdown", @@ -28,7 +32,8 @@ "type-check": "tsc --noEmit", "coverage": "tsx scripts/coverage.ts", "generate-docs": "typedoc", - "format": "biome format --fix" + "format": "biome format --fix", + "check": "biome check --fix" }, "keywords": [ "effect", diff --git a/src/experimental/environment.ts b/src/experimental/environment.ts index 7931f73..1f18cb2 100644 --- a/src/experimental/environment.ts +++ b/src/experimental/environment.ts @@ -33,8 +33,8 @@ export class PlaywrightEnvironment extends Context.Tag( * @example * * ```ts + * import { chromium } from "effect-playwright"; * import { PlaywrightEnvironment } from "effect-playwright/experimental"; - * import { chromium } from "playwright-core"; * * const playwrightEnv = PlaywrightEnvironment.layer(chromium); * @@ -79,8 +79,8 @@ const withBrowserUnscoped = Effect.provideServiceEffect( * @example * * ```ts + * import { chromium } from "effect-playwright"; * import { PlaywrightEnvironment } from "effect-playwright/experimental"; - * import { chromium } from "playwright-core"; * * const env = PlaywrightEnvironment.layer(chromium); * diff --git a/src/index.ts b/src/index.ts index 0639c53..c949e83 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,5 @@ /** - * An Effect-based wrapper for Playwright, bringing the power of functional programming - * and structured concurrency to browser automation. + * An Effect-based wrapper for Playwright. * * ## Features * @@ -14,6 +13,7 @@ * @packageDocumentation */ +export { chromium, firefox, webkit } from "playwright-core"; export * from "./browser"; export { PlaywrightBrowserContext, diff --git a/src/playwright.ts b/src/playwright.ts index 8a99cb3..76deeee 100644 --- a/src/playwright.ts +++ b/src/playwright.ts @@ -26,12 +26,12 @@ export interface PlaywrightService { * {@link launchScoped} instead. * * ```ts + * import { Playwright, chromium } from "effect-playwright"; * import { Effect } from "effect"; - * import { Playwright } from "effect-playwright"; - * import { chromium } from "playwright-core"; * * const program = Effect.gen(function* () { - * const browser = yield* Playwright.launch(chromium); + * const playwright = yield* Playwright; + * const browser = yield* playwright.launch(chromium); * // ... use browser ... * yield* browser.close; * }); @@ -53,12 +53,12 @@ export interface PlaywrightService { * This method automatically closes the browser when the scope is closed. * * ```ts + * import { Playwright, chromium } from "effect-playwright"; * import { Effect } from "effect"; - * import { Playwright } from "effect-playwright"; - * import { chromium } from "playwright-core"; * * const program = Effect.gen(function* () { - * const browser = yield* Playwright.launchScoped(chromium); + * const playwright = yield* Playwright; + * const browser = yield* playwright.launchScoped(chromium); * // Browser will be closed automatically when scope closes * }); * @@ -89,9 +89,8 @@ export interface PlaywrightService { * Closing this context also closes the underlying browser process. * * ```ts + * import { Playwright, chromium } from "effect-playwright"; * import { Effect } from "effect"; - * import { Playwright } from "effect-playwright"; - * import { chromium } from "playwright-core"; * * const program = Effect.gen(function* () { * const playwright = yield* Playwright; @@ -113,6 +112,9 @@ export interface PlaywrightService { * If you call this non-scoped variant inside a scope, add a finalizer for cleanup: * * ```ts + * import { Playwright, chromium } from "effect-playwright"; + * import { Effect } from "effect"; + * * const program = Effect.gen(function* () { * const playwright = yield* Playwright; * const context = yield* playwright.launchPersistentContext( @@ -143,9 +145,8 @@ export interface PlaywrightService { * when the scope is closed. * * ```ts + * import { Playwright, chromium } from "effect-playwright"; * import { Effect } from "effect"; - * import { Playwright } from "effect-playwright"; - * import { chromium } from "playwright-core"; * * const program = Effect.gen(function* () { * const playwright = yield* Playwright;