Skip to content

Commit cc01b18

Browse files
committed
refactor: convert to native ESM
BREAKING CHANGE: The project is now native ESM without a CJS alternative. This is fine since all supported node versions allow `require(esm)`. Also all the dependencies are updated to the latest versions, including cheerio v1.
1 parent c7eb771 commit cc01b18

244 files changed

Lines changed: 1213 additions & 1338 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/upgrading/upgrading_v4.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
id: upgrading-to-v4
3+
title: Upgrading to v4
4+
---
5+
6+
import ApiLink from '@site/src/components/ApiLink';
7+
8+
This page summarizes most of the breaking changes in Crawlee v4.
9+
10+
## ECMAScript modules
11+
12+
Crawlee v4 is a native ESM package now. It can be still consumed from a CJS project, as long as you use TypeScript and Node.js version that supports `require(esm)`.
13+
14+
## Node 22+ required
15+
16+
Support for older node versions was dropped.
17+
18+
## TypeScript 5.8+ required
19+
20+
Support for older TypeScript versions was dropped. Older versions might work too, but only if your project is also ESM.
21+
22+
## Cheerio v1
23+
24+
Previously, we kept the dependency on cheerio locked to the latest RC version, since there were many breaking changes introduced in v1.0. This release bumps cheerio to the stable v1. Also, we now use the default `parse5` internally.

eslint.config.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import tsEslint from 'typescript-eslint';
2+
import tsStylistic from '@stylistic/eslint-plugin-ts';
3+
import apifyJs from '@apify/eslint-config/js';
14
import apify from '@apify/eslint-config/ts';
25
import stylistic from '@stylistic/eslint-plugin';
36
import prettier from 'eslint-config-prettier';
@@ -78,4 +81,13 @@ export default [
7881
'no-undef': 'off',
7982
},
8083
},
84+
// {
85+
// files: ['test/**/*'],
86+
// rules: {
87+
// ...apifyJs.rules,
88+
// '@typescript-eslint/no-floating-promises': 'off',
89+
// 'no-console': 'off',
90+
// 'no-undef': 'off',
91+
// },
92+
// },
8193
];

package.json

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "@crawlee/root",
33
"private": true,
4+
"type": "module",
45
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
56
"workspaces": [
67
"packages/*"
@@ -49,70 +50,73 @@
4950
"release:prod": "yarn build && yarn publish:prod",
5051
"release:pin-versions": "turbo run copy -- -- --pin-versions",
5152
"lint": "eslint \"packages/**/*.ts\" \"test/**/*.ts\"",
52-
"lint:fix": "eslint \"packages/**/*.ts\" \"test/**/*.ts\" --fix",
53+
"lint:fix": "eslint \"packages/**/*.ts\" \"test/**/*.{ts,mjs}\" --fix",
5354
"format": "biome format --write .",
5455
"format:check": "biome format .",
5556
"prepare": "husky"
5657
},
5758
"devDependencies": {
5859
"@apify/eslint-config": "2.0.0",
59-
"@apify/log": "^2.4.0",
60+
"@apify/log": "^2.5.18",
6061
"@apify/tsconfig": "^0.2.0",
6162
"@biomejs/biome": "^2.3.11",
6263
"@commitlint/config-conventional": "^21.0.0",
63-
"@playwright/browser-chromium": "1.62.1",
64-
"@playwright/browser-firefox": "1.62.1",
65-
"@playwright/browser-webkit": "1.62.1",
64+
"@playwright/browser-chromium": "1.61.1",
65+
"@playwright/browser-firefox": "1.61.1",
66+
"@playwright/browser-webkit": "1.61.1",
6667
"@stylistic/eslint-plugin": "5.7.1",
67-
"@types/content-type": "^1.1.5",
68-
"@types/deep-equal": "^1.0.1",
69-
"@types/domhandler": "^2.4.2",
70-
"@types/express": "^5.0.0",
71-
"@types/fs-extra": "^11.0.0",
72-
"@types/inquirer": "^8.2.1",
73-
"@types/is-ci": "^3.0.1",
68+
"@stylistic/eslint-plugin-ts": "^4.2.0",
69+
"@types/content-type": "^1.1.8",
70+
"@types/deep-equal": "^1.0.4",
71+
"@types/domhandler": "^3.1.0",
72+
"@types/express": "^5.0.1",
73+
"@types/fs-extra": "^11.0.4",
74+
"@types/inquirer": "^9.0.8",
75+
"@types/is-ci": "^3.0.4",
7476
"@types/lodash.isequal": "^4.5.8",
75-
"@types/lodash.merge": "^4.6.7",
76-
"@types/mime-types": "^2.1.1",
77+
"@types/lodash.merge": "^4.6.9",
78+
"@types/mime-types": "^2.1.4",
7779
"@types/node": "^24.0.0",
78-
"@types/proper-lockfile": "^4.1.2",
79-
"@types/ps-tree": "^1.1.2",
80-
"@types/rimraf": "^4.0.0",
81-
"@types/sax": "^1.0.0",
82-
"@types/semver": "^7.3.12",
83-
"@types/stream-json": "^1.7.2",
84-
"@types/yargs": "^17.0.26",
80+
"@types/proper-lockfile": "^4.1.4",
81+
"@types/ps-tree": "^1.1.6",
82+
"@types/rimraf": "^4.0.5",
83+
"@types/sax": "^1.2.7",
84+
"@types/semver": "^7.7.0",
85+
"@types/stream-json": "^1.7.8",
86+
"@types/whatwg-mimetype": "^3.0.2",
87+
"@types/yargs": "^17.0.33",
8588
"@vitest/coverage-v8": "^4.0.16",
8689
"apify": "*",
87-
"apify-node-curl-impersonate": "^1.0.15",
90+
"apify-node-curl-impersonate": "^1.0.23",
8891
"basic-auth-parser": "^0.0.2",
89-
"body-parser": "^2.0.0",
90-
"camoufox-js": "^0.12.0",
92+
"body-parser": "^2.2.0",
93+
"camoufox-js": "^0.11.0",
9194
"commitlint": "^21.0.0",
9295
"cross-env": "^10.0.0",
93-
"deep-equal": "^2.0.5",
96+
"deep-equal": "^2.2.3",
9497
"eslint": "9.39.1",
9598
"eslint-config-prettier": "10.1.8",
96-
"express": "^4.18.1",
97-
"fs-extra": "^11.0.0",
99+
"express": "^5.1.0",
100+
"fs-extra": "^11.3.0",
98101
"gen-esm-wrapper": "^1.1.3",
99102
"globals": "^17.0.0",
100103
"globby": "^15.0.0",
101-
"got": "^13.0.0",
102-
"husky": "^9.0.11",
103-
"is-ci": "^4.0.0",
104-
"lerna": "^10.0.0",
104+
"got": "^14.4.7",
105+
"husky": "^9.1.7",
106+
"is-ci": "^4.1.0",
107+
"lerna": "^9.0.7",
105108
"lint-staged": "^17.0.0",
106-
"nock": "^13.4.0",
107-
"playwright": "1.62.1",
109+
"nock": "^13.5.6",
110+
"playwright": "1.61.1",
108111
"portastic": "^1.0.1",
109-
"proxy": "^1.0.2",
110-
"puppeteer": "25.8.0",
111-
"rimraf": "^6.0.0",
112-
"tsx": "^4.4.0",
113-
"turbo": "^2.1.0",
112+
"proxy": "^2.2.0",
113+
"puppeteer": "25.3.0",
114+
"rimraf": "^6.0.1",
115+
"tsx": "^4.19.4",
116+
"turbo": "^2.5.3",
114117
"typescript": "^6.0.0",
115118
"typescript-eslint": "8.46.4",
119+
"vite-tsconfig-paths": "^5.1.4",
116120
"vitest": "^4.0.16",
117121
"zod": "^4.0.0"
118122
},
@@ -122,15 +126,14 @@
122126
"resolutions": {
123127
"tmp": "^0.2.7",
124128
"@puppeteer/browsers": "^3.0.4",
125-
"playwright-core": "1.62.1",
129+
"playwright-core": "1.61.1",
126130
"form-data": "^4.0.6",
127131
"tar": "^7.5.16",
128-
"lerna/js-yaml": "^4.2.0",
129-
"node-gyp": "^12.1.0"
132+
"lerna/js-yaml": "^4.2.0"
130133
},
131134
"packageManager": "yarn@4.10.3",
132135
"volta": {
133-
"node": "24.19.0",
136+
"node": "24.18.0",
134137
"yarn": "4.10.3"
135138
}
136139
}
Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
{
22
"name": "@crawlee/basic",
3-
"version": "3.18.1",
3+
"version": "3.17.0",
44
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
55
"engines": {
6-
"node": ">=16.0.0"
6+
"node": ">=22.0.0"
77
},
8-
"main": "./dist/index.js",
9-
"module": "./dist/index.mjs",
10-
"types": "./dist/index.d.ts",
8+
"type": "module",
119
"exports": {
12-
".": {
13-
"import": "./dist/index.mjs",
14-
"require": "./dist/index.js",
15-
"types": "./dist/index.d.ts"
16-
},
10+
".": "./dist/index.js",
1711
"./package.json": "./package.json"
1812
},
1913
"author": {
@@ -38,26 +32,26 @@
3832
"scripts": {
3933
"build": "yarn clean && yarn compile && yarn copy",
4034
"clean": "rimraf ./dist",
41-
"compile": "tsc -p tsconfig.build.json && gen-esm-wrapper ./dist/index.js ./dist/index.mjs",
35+
"compile": "tsc -p tsconfig.build.json",
4236
"copy": "tsx ../../scripts/copy.ts"
4337
},
4438
"publishConfig": {
4539
"access": "public"
4640
},
4741
"dependencies": {
4842
"@apify/datastructures": "^2.0.0",
49-
"@apify/log": "^2.4.0",
50-
"@apify/timeout": "^0.4.0",
51-
"@apify/utilities": "^2.7.10",
52-
"@crawlee/core": "3.18.1",
53-
"@crawlee/types": "3.18.1",
54-
"@crawlee/utils": "3.18.1",
55-
"csv-stringify": "^6.2.0",
56-
"fs-extra": "^11.0.0",
43+
"@apify/log": "^2.5.18",
44+
"@apify/timeout": "^0.3.2",
45+
"@apify/utilities": "^2.15.5",
46+
"@crawlee/core": "3.17.0",
47+
"@crawlee/types": "3.17.0",
48+
"@crawlee/utils": "3.17.0",
49+
"csv-stringify": "^6.5.2",
50+
"fs-extra": "^11.3.0",
5751
"got-scraping": "^4.2.1",
58-
"ow": "^0.28.1",
59-
"tldts": "^7.0.0",
60-
"tslib": "^2.4.0",
61-
"type-fest": "^4.0.0"
52+
"ow": "^2.0.0",
53+
"tldts": "^7.0.6",
54+
"tslib": "^2.8.1",
55+
"type-fest": "^4.41.0"
6256
}
6357
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export * from '@crawlee/core';
2-
export * from './internals/basic-crawler';
3-
export * from './internals/constants';
2+
export * from './internals/basic-crawler.js';
3+
export * from './internals/constants.js';
44
export { CheerioRoot, CheerioAPI, Cheerio, Element } from '@crawlee/utils';

packages/basic-crawler/src/internals/basic-crawler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { writeFile } from 'node:fs/promises';
12
import { dirname } from 'node:path';
23

34
import type {
@@ -58,7 +59,7 @@ import {
5859
import type { Awaitable, BatchAddRequestsResult, Dictionary, SetStatusMessageOptions } from '@crawlee/types';
5960
import { getObjectType, isAsyncIterable, isIterable, RobotsTxtFile, ROTATE_PROXY_ERRORS, sleep } from '@crawlee/utils';
6061
import { stringify } from 'csv-stringify/sync';
61-
import { ensureDir, writeFile, writeJSON } from 'fs-extra';
62+
import { ensureDir, writeJSON } from 'fs-extra/esm';
6263
import ow, { ArgumentError } from 'ow';
6364
import { getDomain } from 'tldts';
6465
import type { SetRequired } from 'type-fest';
@@ -69,7 +70,7 @@ import defaultLog, { LogLevel } from '@apify/log';
6970
import { addTimeoutToPromise, TimeoutError, tryCancel } from '@apify/timeout';
7071
import { cryptoRandomObjectId } from '@apify/utilities';
7172

72-
import { createSendRequest } from './send-request';
73+
import { createSendRequest } from './send-request.js';
7374

7475
export interface BasicCrawlingContext<UserData extends Dictionary = Dictionary>
7576
extends CrawlingContext<BasicCrawler, UserData> {

packages/basic-crawler/src/internals/send-request.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import {
55
type Request,
66
type Session,
77
} from '@crawlee/core';
8-
// @ts-expect-error This throws a compilation error due to got-scraping being ESM only but we only import types, so its alllll gooooood
9-
import type { GotResponse, Method } from 'got-scraping';
8+
import type { Method, Response as GotResponse } from 'got-scraping';
109

1110
/**
1211
* Prepares a function to be used as the `sendRequest` context helper.
@@ -49,6 +48,6 @@ export function createSendRequest(
4948
// Fill in body as the last step - `processHttpRequestOptions` may use either `body`, `json` or `form` so we cannot override it beforehand
5049
requestOptions.body ??= originRequest.payload;
5150

52-
return httpClient.sendRequest<any>(requestOptions);
51+
return httpClient.sendRequest<any>(requestOptions) as unknown as GotResponse<Response>;
5352
};
5453
}

packages/basic-crawler/test/batch-add-requests.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { BasicCrawler } from '@crawlee/basic';
22

3-
import { MemoryStorageEmulator } from '../../../test/shared/MemoryStorageEmulator';
3+
import { MemoryStorageEmulator } from '../../../test/shared/MemoryStorageEmulator.js';
44

55
describe('BasicCrawler#addRequests with big batch sizes', () => {
66
const localStorageEmulator = new MemoryStorageEmulator();

packages/basic-crawler/test/migration.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { Log } from '@apify/log';
22
import log from '@apify/log';
33

4-
import { MemoryStorageEmulator } from '../../../test/shared/MemoryStorageEmulator';
5-
import { BasicCrawler, RequestList } from '../src/index';
4+
import { MemoryStorageEmulator } from '../../../test/shared/MemoryStorageEmulator.js';
5+
import { BasicCrawler, RequestList } from '../src/index.js';
66

77
const localStorageEmulator = new MemoryStorageEmulator();
88

packages/browser-crawler/package.json

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
{
22
"name": "@crawlee/browser",
3-
"version": "3.18.1",
3+
"version": "3.17.0",
44
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
55
"engines": {
6-
"node": ">=16.0.0"
6+
"node": ">=22.0.0"
77
},
8-
"main": "./dist/index.js",
9-
"module": "./dist/index.mjs",
10-
"types": "./dist/index.d.ts",
8+
"type": "module",
119
"exports": {
12-
".": {
13-
"import": "./dist/index.mjs",
14-
"require": "./dist/index.js",
15-
"types": "./dist/index.d.ts"
16-
},
10+
".": "./dist/index.js",
1711
"./package.json": "./package.json"
1812
},
1913
"keywords": [
@@ -46,21 +40,21 @@
4640
"scripts": {
4741
"build": "yarn clean && yarn compile && yarn copy",
4842
"clean": "rimraf ./dist",
49-
"compile": "tsc -p tsconfig.build.json && gen-esm-wrapper ./dist/index.js ./dist/index.mjs",
43+
"compile": "tsc -p tsconfig.build.json",
5044
"copy": "tsx ../../scripts/copy.ts"
5145
},
5246
"publishConfig": {
5347
"access": "public"
5448
},
5549
"dependencies": {
56-
"@apify/timeout": "^0.4.0",
57-
"@crawlee/basic": "3.18.1",
58-
"@crawlee/browser-pool": "3.18.1",
59-
"@crawlee/types": "3.18.1",
60-
"@crawlee/utils": "3.18.1",
61-
"ow": "^0.28.1",
62-
"tslib": "^2.4.0",
63-
"type-fest": "^4.0.0"
50+
"@apify/timeout": "^0.3.2",
51+
"@crawlee/basic": "3.17.0",
52+
"@crawlee/browser-pool": "3.17.0",
53+
"@crawlee/types": "3.17.0",
54+
"@crawlee/utils": "3.17.0",
55+
"ow": "^2.0.0",
56+
"tslib": "^2.8.1",
57+
"type-fest": "^4.41.0"
6458
},
6559
"peerDependencies": {
6660
"playwright": "*",

0 commit comments

Comments
 (0)