diff --git a/compat/README.md b/compat/README.md new file mode 100644 index 0000000000000..a72ecab4e8a3c --- /dev/null +++ b/compat/README.md @@ -0,0 +1,16 @@ +# Compatibility layer + +This directory provides an additional compatibility layer between ES modules and CommonJS. + +## Why? + +Both `./cjs/compat.ts` and `./esm/compat.ts` are written as ES modules, but `./cjs/compat.ts` can additionally use NodeJS CommonJS globals such as `__dirname` and `require` while these are disabled in ES module mode. For more information, see [Differences between ES modules and CommonJS](https://nodejs.org/api/esm.html#differences-between-es-modules-and-commonjs). + +## Adding exports + +In order to add exports, two things need to be done: + +- The exports must be declared in `src/compat.ts`. +- The exports must be realized in `./cjs/compat.ts` and `./esm/compat.ts`. + +In the event `compat.ts` becomes too large, you can place declarations in another file. Just make sure `./cjs`, `./esm`, and `src` have the same structure. diff --git a/compat/cjs/compat.ts b/compat/cjs/compat.ts new file mode 100644 index 0000000000000..5b51524dd12ab --- /dev/null +++ b/compat/cjs/compat.ts @@ -0,0 +1 @@ +export const puppeteerDirname = __dirname; diff --git a/compat/cjs/tsconfig.json b/compat/cjs/tsconfig.json new file mode 100644 index 0000000000000..0de31b76c4440 --- /dev/null +++ b/compat/cjs/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "../../lib/cjs/puppeteer", + "module": "CommonJS" + }, + "references": [ + { "path": "../../vendor/tsconfig.cjs.json"} + ] +} diff --git a/compat/esm/compat.ts b/compat/esm/compat.ts new file mode 100644 index 0000000000000..2ddd69ef0e448 --- /dev/null +++ b/compat/esm/compat.ts @@ -0,0 +1,4 @@ +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; + +export const puppeteerDirname = dirname(fileURLToPath(import.meta.url)); diff --git a/compat/esm/tsconfig.json b/compat/esm/tsconfig.json new file mode 100644 index 0000000000000..42b320fcd3f28 --- /dev/null +++ b/compat/esm/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "composite": true, + "outDir": "../../lib/esm/puppeteer", + "module": "esnext" + }, + "references": [{ "path": "../../vendor/tsconfig.esm.json" }] +} diff --git a/package.json b/package.json index 18a1c99337f8f..8c6d41b84d82e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,12 @@ "name": "puppeteer", "version": "13.2.0", "description": "A high-level API to control headless Chrome over the DevTools Protocol", + "type": "commonjs", "main": "./cjs-entry.js", + "exports": { + "import": "./lib/esm/puppeteer/node.js", + "require": "./cjs-entry.js" + }, "types": "lib/types.d.ts", "repository": "github:puppeteer/puppeteer", "engines": { @@ -29,15 +34,18 @@ "lint": "npm run eslint && npm run build && npm run doc && npm run markdownlint", "doc": "node utils/doclint/cli.js", "clean-lib": "rimraf lib", - "build": "npm run tsc && npm run generate-d-ts", - "tsc": "npm run clean-lib && tsc --version && npm run tsc-cjs && npm run tsc-esm", + "build": "npm run tsc && npm run generate-d-ts && npm run generate-pkg-json", + "tsc": "npm run clean-lib && tsc --version && (npm run tsc-cjs & npm run tsc-esm) && (npm run tsc-compat-cjs & npm run tsc-compat-esm)", "tsc-cjs": "tsc -b src/tsconfig.cjs.json", "tsc-esm": "tsc -b src/tsconfig.esm.json", + "tsc-compat-cjs": "tsc -b compat/cjs/tsconfig.json", + "tsc-compat-esm": "tsc -b compat/esm/tsconfig.json", "apply-next-version": "node utils/apply_next_version.js", "test-install": "scripts/test-install.sh", "clean-docs": "rimraf website/docs && rimraf docs-api-json", "generate-d-ts": "npm run clean-docs && api-extractor run --local --verbose", "generate-docs": "npm run generate-d-ts && api-documenter markdown -i docs-api-json -o website/docs && node utils/remove-tag.js", + "generate-pkg-json": "echo '{\"type\": \"module\"}' > lib/esm/package.json", "ensure-correct-devtools-protocol-revision": "ts-node -s scripts/ensure-correct-devtools-protocol-package", "ensure-pinned-deps": "ts-node -s scripts/ensure-pinned-deps", "test-types-file": "ts-node -s scripts/test-ts-definition-files.ts", diff --git a/src/common/Debug.ts b/src/common/Debug.ts index 8ff124b094b3b..ce01a7d7dd208 100644 --- a/src/common/Debug.ts +++ b/src/common/Debug.ts @@ -55,7 +55,9 @@ import { isNode } from '../environment.js'; export const debug = (prefix: string): ((...args: unknown[]) => void) => { if (isNode) { // eslint-disable-next-line @typescript-eslint/no-var-requires - return require('debug')(prefix); + return async (...logArgs: unknown[]) => { + (await import('debug')).default(prefix)(logArgs); + }; } return (...logArgs: unknown[]): void => { diff --git a/src/compat.ts b/src/compat.ts new file mode 100644 index 0000000000000..873dcea7966e5 --- /dev/null +++ b/src/compat.ts @@ -0,0 +1,3 @@ +declare const puppeteerDirname: string; + +export { puppeteerDirname }; diff --git a/src/initialize-node.ts b/src/initialize-node.ts index e5336654034d4..17f410275131a 100644 --- a/src/initialize-node.ts +++ b/src/initialize-node.ts @@ -18,9 +18,10 @@ import { PuppeteerNode } from './node/Puppeteer.js'; import { PUPPETEER_REVISIONS } from './revisions.js'; import pkgDir from 'pkg-dir'; import { Product } from './common/Product.js'; +import { puppeteerDirname } from './compat.js'; export const initializePuppeteerNode = (packageName: string): PuppeteerNode => { - const puppeteerRootDirectory = pkgDir.sync(__dirname); + const puppeteerRootDirectory = pkgDir.sync(puppeteerDirname); let preferredRevision = PUPPETEER_REVISIONS.chromium; const isPuppeteerCore = packageName === 'puppeteer-core'; diff --git a/tsconfig.json b/tsconfig.json index 0fe7e06ad83c7..0abb2d09decad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,5 +12,5 @@ */ "module": "esnext" }, - "include": ["src"] + "include": ["src"], }