Skip to content

Commit 505d94a

Browse files
authored
chore: drop dependency on playwright-core in all our packages (#2318)
This patch: - drops dependency on playwright-core in all our packages. Instead of the dependency, packages are now built with `//packages/build_package.sh` script. - unifies `browsers.json` - now there's a single `//browsers.json` file that is used to manage browser revisions. This patch temporary switches canary publishing to `--dryn-run` from CI/CD so that we can verify that it does sane things. We'll unify all our package management scripts under `//packages/` in a follow-up. Fixes #2268
1 parent 2ede4bc commit 505d94a

31 files changed

+291
-149
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ yarn.lock
1616
/src/firefox/protocol.ts
1717
/src/webkit/protocol.ts
1818
lib/
19-
playwright-*.tgz
2019
/types/*

.npmignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# NOTE: .npmignore is copied over to every subpackage in //packages when NPM packages
2+
# are built.
3+
#
14
# this ignores everything by default, except for package.json and LICENSE and README.md
25
# see https://docs.npmjs.com/misc/developers
36
**/*
@@ -10,8 +13,11 @@ lib/injected/
1013
!types/*
1114
!index.d.ts
1215

13-
# root for "playwright-core" package
1416
!index.js
17+
!install.js
18+
!README.md
19+
!LICENSE
20+
!NOTICE
1521

1622
# browser descriptor
1723
!browsers.json
File renamed without changes.

index-for-dev.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const { Playwright } = require('./lib/server/playwright');
1818
const { Electron } = require('./lib/server/electron');
1919
const path = require('path');
2020

21-
const playwrightRoot = path.join(__dirname, 'packages', 'playwright');
22-
const playwright = new Playwright(playwrightRoot, require(path.join(playwrightRoot, 'browsers.json'))['browsers']);
21+
const playwright = new Playwright(__dirname, require(path.join(__dirname, 'browsers.json'))['browsers']);
2322
playwright.electron = new Electron();
2423
module.exports = playwright;

install-from-github.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ async function downloadAllBrowsersAndGenerateProtocolTypes() {
6464
const { installBrowsersWithProgressBar } = require('./lib/install/installer');
6565
const protocolGenerator = require('./utils/protocol-types-generator');
6666
const browserPaths = require('./lib/install/browserPaths');
67-
const playwrightRoot = path.join(__dirname, 'packages', 'playwright');
68-
const browsersPath = browserPaths.browsersPath(playwrightRoot);
69-
const browsers = require(path.join(playwrightRoot, 'browsers.json'))['browsers'];
70-
await installBrowsersWithProgressBar(playwrightRoot);
67+
const browsersPath = browserPaths.browsersPath(__dirname);
68+
const browsers = require(path.join(__dirname, 'browsers.json'))['browsers'];
69+
await installBrowsersWithProgressBar(__dirname);
7170
for (const browser of browsers) {
7271
const browserPath = browserPaths.browserDirectory(browsersPath, browser);
7372
await protocolGenerator.generateProtocol(browser.name, browserPaths.executablePath(browserPath, browser)).catch(console.warn);

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"name": "playwright-core",
2+
"name": "playwright-internal",
3+
"private": true,
34
"version": "1.0.0-post",
45
"description": "A high-level API to automate web browsers",
56
"repository": "github:Microsoft/playwright",

packages/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Managing and Publishing Playwright Packages
2+
3+
## Overview
4+
5+
- Playwright ships multiple packages to NPM. All packges that are published to NPM are listed as folders under [`//packages/`](../packages).
6+
- Playwright's [root package.json](../package.json) is **never published to NPM**. It is only used for devmode, e.g. when running `npm install` with no arguments or installing from github.
7+
- Playwright dependencies for all packages are the same and are managed with the [`root package.json`](../package.json).
8+
- Playwright browser versions for all packages are the same and are managed with the [`browsers.json`](../browsers.json).
9+
10+
> **NOTE** As of May 20, 2020, the only exception is the `playwright-electron` package that
11+
> doesn't follow the pack and is published manually. This is due to it's pre-1.0 status.
12+
13+
14+
## Building NPM package
15+
16+
To build a package that will be shipped to NPM, use [`//packages/build_package.js`](./build_package.js) script.
17+
The script populates package folder with contents, and then uses `npm pack` to archive the folder.
18+
19+
As of May 20, 2020, [`//packages/build_package.js`](./build_package.js) does the following:
20+
- copies certain files and folders from `playwright-internal` to the subpackage (e.g. `//lib`, `//types`, `//LICENSE` etc)
21+
- generates `package.json` and puts it in the subpackage
22+
- generates `browsers.json` and puts it in the subpackage
23+
- uses `npm pack` to pack the subpackage folder
24+
- removes all the files that were added during the process
25+
26+
To build `playwright` package and save result as `./playwright.tgz` file:
27+
28+
```sh
29+
$ ./packages/build_package.js playwright ./playwright.tgz
30+
```
31+
32+
To debug what files are put into the folder, use `--no-cleanup` flag and inspect the package folder:
33+
34+
```sh
35+
$ ./packages/build_package.js playwright ./playwright.tgz --no-cleanup
36+
$ ls ./packages/playwright # inspect the folder
37+
```
38+
39+
40+
## Testing packages
41+
42+
To test packages, use [`//tests/installation-tests/installation-tests.sh`](../tests/installation-tests/installation-tests.sh).
43+
44+
45+
## Publishing packages
46+
47+
All package publishing happens **exclusively** over CI/CD using the [`//utils/publish_all_packages.sh`](../utils/publish_all_packages.sh) script.

packages/build_package.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Copyright (c) Microsoft Corporation.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
const fs = require('fs');
18+
const path = require('path');
19+
const rmSync = require('rimraf').sync;
20+
const ncp = require('ncp');
21+
const {spawnSync} = require('child_process');
22+
const util = require('util');
23+
24+
const writeFileAsync = util.promisify(fs.writeFile.bind(fs));
25+
const cpAsync = util.promisify(ncp);
26+
27+
const SCRIPT_NAME = path.basename(__filename);
28+
const ROOT_PATH = path.join(__dirname, '..');
29+
30+
const PACKAGE_FILES = ['lib', 'types', 'NOTICE', 'LICENSE', '.npmignore'];
31+
32+
const PACKAGES = {
33+
'playwright': {
34+
description: 'A high-level API to automate web browsers',
35+
whitelistedBrowsers: ['chromium', 'firefox', 'webkit'],
36+
// We copy README.md additionally for Playwright so that it looks nice on NPM.
37+
files: [...PACKAGE_FILES, 'README.md'],
38+
},
39+
'playwright-core': {
40+
description: 'A high-level API to automate web browsers',
41+
whitelistedBrowsers: [],
42+
files: PACKAGE_FILES,
43+
},
44+
'playwright-webkit': {
45+
description: 'A high-level API to automate WebKit',
46+
whitelistedBrowsers: ['webkit'],
47+
files: PACKAGE_FILES,
48+
},
49+
'playwright-firefox': {
50+
description: 'A high-level API to automate Firefox',
51+
whitelistedBrowsers: ['firefox'],
52+
files: PACKAGE_FILES,
53+
},
54+
'playwright-chromium': {
55+
description: 'A high-level API to automate Chromium',
56+
whitelistedBrowsers: ['chromium'],
57+
files: PACKAGE_FILES,
58+
},
59+
};
60+
61+
const cleanupPaths = [];
62+
63+
// 1. Parse CLI arguments
64+
const args = process.argv.slice(2);
65+
if (args.some(arg => arg === '--help')) {
66+
console.log(usage());
67+
process.exit(1);
68+
} else if (args.length < 1) {
69+
console.log(`Please specify package name, e.g. 'playwright' or 'playwright-chromium'.`);
70+
console.log(`Try running ${SCRIPT_NAME} --help`);
71+
process.exit(1);
72+
} else if (args.length < 2) {
73+
console.log(`Please specify output path`);
74+
console.log(`Try running ${SCRIPT_NAME} --help`);
75+
process.exit(1);
76+
}
77+
78+
// 2. Setup cleanup if needed
79+
if (!args.some(arg => arg === '--no-cleanup')) {
80+
process.on('exit', () => {
81+
cleanupPaths.forEach(cleanupPath => rmSync(cleanupPath, {}));
82+
});
83+
process.on('SIGINT', () => process.exit(2));
84+
process.on('SIGHUP', () => process.exit(3));
85+
process.on('SIGTERM', () => process.exit(4));
86+
process.on('uncaughtException', error => {
87+
console.error(error);
88+
process.exit(5);
89+
});
90+
process.on('unhandledRejection', error => {
91+
console.error(error);
92+
process.exit(6);
93+
});
94+
}
95+
96+
const packageName = args[0];
97+
const outputPath = path.resolve(args[1]);
98+
const packagePath = path.join(__dirname, packageName);
99+
const package = PACKAGES[packageName];
100+
if (!package) {
101+
console.log(`ERROR: unknown package ${packageName}`);
102+
process.exit(1);
103+
}
104+
105+
(async () => {
106+
// 3. Copy package files.
107+
for (const file of package.files)
108+
await copyToPackage(file);
109+
110+
// 4. Generate package.json
111+
const packageJSON = require(path.join(ROOT_PATH, 'package.json'));
112+
await writeToPackage('package.json', JSON.stringify({
113+
name: packageName,
114+
version: packageJSON.version,
115+
description: package.description,
116+
repository: packageJSON.repository,
117+
engines: packageJSON.engines,
118+
homepage: packageJSON.homepage,
119+
main: 'index.js',
120+
scripts: {
121+
install: 'node install.js',
122+
},
123+
author: packageJSON.author,
124+
license: packageJSON.license,
125+
dependencies: packageJSON.dependencies
126+
}, null, 2));
127+
128+
// 5. Generate browsers.json
129+
const browsersJSON = require(path.join(ROOT_PATH, 'browsers.json'));
130+
browsersJSON.browsers = browsersJSON.browsers.filter(browser => package.whitelistedBrowsers.includes(browser.name));
131+
await writeToPackage('browsers.json', JSON.stringify(browsersJSON, null, 2));
132+
133+
// 6. Run npm pack
134+
const {stdout, stderr, status} = spawnSync('npm', ['pack'], {cwd: packagePath, encoding: 'utf8'});
135+
if (status !== 0) {
136+
console.log(`ERROR: "npm pack" failed`);
137+
console.log(stderr);
138+
process.exit(1);
139+
}
140+
const tgzName = stdout.trim();
141+
142+
// 7. Move result to the outputPath
143+
fs.renameSync(path.join(packagePath, tgzName), outputPath);
144+
console.log(outputPath);
145+
})();
146+
147+
async function writeToPackage(fileName, content) {
148+
const toPath = path.join(packagePath, fileName);
149+
cleanupPaths.push(toPath);
150+
console.error(`- generating: //${path.relative(ROOT_PATH, toPath)}`);
151+
await writeFileAsync(toPath, content);
152+
}
153+
154+
async function copyToPackage(fileOrDirectoryName) {
155+
const fromPath = path.join(ROOT_PATH, fileOrDirectoryName);
156+
const toPath = path.join(packagePath, fileOrDirectoryName);
157+
cleanupPaths.push(toPath);
158+
console.error(`- copying: //${path.relative(ROOT_PATH, fromPath)} -> //${path.relative(ROOT_PATH, toPath)}`);
159+
await cpAsync(fromPath, toPath);
160+
}
161+
162+
function usage() {
163+
return `
164+
usage: ${SCRIPT_NAME} <package-name> <output-path> [--no-cleanup]
165+
166+
Creates a .tgz of the package and saves it at the given output path
167+
168+
--no-cleanup skip cleaning up generated files from package directory
169+
170+
Example:
171+
${SCRIPT_NAME} playwright ./playwright.tgz
172+
`;
173+
}
174+

packages/playwright-chromium/browsers.json

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)