Skip to content

Commit e7b93e3

Browse files
authored
feat(browser-ui): add umd bundle config (#107)
* fix(browser): press test case * feat(browser-ui): add browser-ui umd bundle file * feat(browser-ui): add browser-ui umd bundle test html * feat(browser-ui): add unpkg cdn use case --------- Co-authored-by: skychx <skychx.hotmail.com>
1 parent 21e4331 commit e7b93e3

File tree

11 files changed

+293
-8
lines changed

11 files changed

+293
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pnpm run build
6363
pnpm run test
6464

6565
# Lint code
66-
pnpm run lint
66+
pnpm run format
6767
```
6868

6969
<br />

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pnpm run build
6363
pnpm run test
6464

6565
# 代码检查
66-
pnpm run lint
66+
pnpm run format
6767
```
6868

6969
<br />

packages/browser-ui/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,33 @@ BrowserUI.create({
4040
});
4141
```
4242

43+
Or use the unpkg CDN to use it on any webpage:
44+
45+
- **CDN URL**: https://unpkg.com/@agent-infra/browser/dist/bundle/index.js
46+
47+
```html
48+
<!doctype html>
49+
<html lang="en">
50+
<body>
51+
<div id="browserContainer"></div>
52+
<script src="https://unpkg.com/@agent-infra/browser/dist/bundle/index.js"></script>
53+
<script>
54+
const BrowserUI = window.agent_infra_browser_ui.BrowserUI;
55+
56+
BrowserUI.create({
57+
root: document.getElementById('browserContainer'),
58+
browserOptions: {
59+
connect: {
60+
// @ts-ignore
61+
browserWSEndpoint: 'https://example.com/ws/url',
62+
},
63+
},
64+
});
65+
</script>
66+
</body>
67+
</html>
68+
```
69+
4370
A complete usable example, which can be run directly with `npm run dev` in the current directory or viewed in the `/examples` directory within the package.
4471

4572
## Features

packages/browser-ui/README.zh-CN.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,37 @@ BrowserUI.create({
4040
});
4141
```
4242

43+
或者直接使用 unpkg CDN 在任意网页中使用:
44+
45+
- **CDN URL**: https://unpkg.com/@agent-infra/browser/dist/bundle/index.js
46+
47+
```html
48+
<!doctype html>
49+
<html lang="en">
50+
<body>
51+
<div id="browserContainer"></div>
52+
<script src="https://unpkg.com/@agent-infra/browser/dist/bundle/index.js"></script>
53+
<script>
54+
const BrowserUI = window.agent_infra_browser_ui.BrowserUI;
55+
56+
BrowserUI.create({
57+
root: document.getElementById('browserContainer'),
58+
browserOptions: {
59+
connect: {
60+
// @ts-ignore
61+
browserWSEndpoint: 'https://example.com/ws/url',
62+
},
63+
},
64+
});
65+
</script>
66+
</body>
67+
</html>
68+
```
69+
4370
完整的可用示例,可直接在当前目录下运行 `npm run dev` 或查看包中的 `/examples` 目录。
4471

72+
<br />
73+
4574
## 核心功能
4675

4776
关于所有功能的详细文档和 API 参考,请访问我们的[完整文档](https://github.com/agent-infra/browser/blob/main/docs/browser-ui.zh-CN.md)
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright (c) 2025 Bytedance, Inc. and its affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import puppeteer from 'puppeteer-core';
6+
import { createServer } from 'http';
7+
import { readFile, stat } from 'fs/promises';
8+
import { URL, fileURLToPath } from 'url';
9+
import { join, dirname } from 'path';
10+
11+
async function main() {
12+
console.log('🚀 launch ...');
13+
14+
const browser = await puppeteer.launch({
15+
executablePath:
16+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
17+
headless: false,
18+
defaultViewport: {
19+
width: 900,
20+
height: 900,
21+
deviceScaleFactor: 0,
22+
},
23+
args: [
24+
'--mute-audio',
25+
'--no-default-browser-check',
26+
'--window-size=900,990',
27+
'--remote-allow-origins=http://127.0.0.1:3000',
28+
'https://www.bytedance.com/en/',
29+
],
30+
ignoreDefaultArgs: ['--enable-automation'],
31+
});
32+
33+
const wsEndpoint = browser.wsEndpoint();
34+
35+
console.log('✅ launched successfully!');
36+
console.log('📡 CDP WebSocket:', wsEndpoint);
37+
38+
const port = 3000;
39+
const server = createServer(async (req, res) => {
40+
try {
41+
console.log(`Request: ${req.method} ${req.url}`);
42+
43+
if (req.url === '/' || req.url === '/index.html') {
44+
const indexPath = new URL('./index.html', import.meta.url).pathname;
45+
console.log(`Reading file: ${indexPath}`);
46+
47+
let html = await readFile(indexPath, 'utf-8');
48+
console.log('File read successfully');
49+
50+
// Replace the import.meta.WSEndpoint with the actual wsEndpoint
51+
html = html.replace(
52+
'import.meta.WSEndpoint',
53+
JSON.stringify(wsEndpoint),
54+
);
55+
56+
console.log('HTML length:', html.length);
57+
58+
res.writeHead(200, { 'Content-Type': 'text/html' });
59+
res.end(html);
60+
} else if (req.url?.startsWith('/dist/')) {
61+
// Handle static files from /dist/ directory
62+
const __filename = fileURLToPath(import.meta.url);
63+
const __dirname = dirname(__filename);
64+
const staticPath = join(
65+
__dirname,
66+
'..',
67+
'..',
68+
'dist',
69+
req.url.replace('/dist/', ''),
70+
);
71+
72+
console.log(`Static file request: ${staticPath}`);
73+
74+
try {
75+
const fileStat = await stat(staticPath);
76+
if (fileStat.isFile()) {
77+
const content = await readFile(staticPath);
78+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
79+
res.end(content);
80+
return;
81+
}
82+
} catch (staticError) {
83+
console.error('Static file not found:', staticError);
84+
}
85+
86+
res.writeHead(404, { 'Content-Type': 'text/plain' });
87+
res.end('Static file not found');
88+
} else {
89+
console.log('404 for:', req.url);
90+
res.writeHead(404, { 'Content-Type': 'text/plain' });
91+
res.end('Not Found');
92+
}
93+
} catch (error) {
94+
console.error('Server error:', error);
95+
res.writeHead(500, { 'Content-Type': 'text/plain' });
96+
res.end(`Internal Server Error: ${(error as Error).message}`);
97+
}
98+
});
99+
100+
server.listen(port, () => {
101+
console.log(`🌐 Server running at http://localhost:${port}`);
102+
console.log('🔄 Ctrl+C to exit...\n');
103+
});
104+
105+
const cleanup = async () => {
106+
try {
107+
console.log('\n🛑 closing server and browser...');
108+
if (server) {
109+
server.close();
110+
}
111+
if (browser) {
112+
await browser.close();
113+
}
114+
} catch (e) {
115+
// ignore
116+
} finally {
117+
process.exit(0);
118+
}
119+
};
120+
121+
process.on('SIGINT', cleanup);
122+
process.on('SIGTERM', cleanup);
123+
}
124+
125+
main().catch(console.error);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>CanvasBrowser Demo</title>
7+
<style>
8+
body {
9+
margin: 0;
10+
padding: 20px;
11+
font-family:
12+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
13+
}
14+
</style>
15+
</head>
16+
17+
<body>
18+
<div id="browserContainer">
19+
<!-- Browser UI will be automatically mounted here -->
20+
</div>
21+
22+
<script src="../dist/bundle/index.js"></script>
23+
<script>
24+
const container = document.getElementById('browserContainer');
25+
if (!container) {
26+
throw new Error('Browser container element not found');
27+
}
28+
29+
const BrowserUI = window.agent_infra_browser_ui.BrowserUI;
30+
31+
BrowserUI.create({
32+
root: container,
33+
browserOptions: {
34+
connect: {
35+
// @ts-ignore
36+
browserWSEndpoint: import.meta.WSEndpoint,
37+
defaultViewport: {
38+
width: 900,
39+
height: 900,
40+
},
41+
},
42+
searchEngine: 'baidu',
43+
},
44+
});
45+
</script>
46+
</body>
47+
</html>
File renamed without changes.

packages/browser-ui/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
],
3030
"scripts": {
3131
"prepublishOnly": "pnpm run build",
32-
"build": "rslib build",
33-
"dev": "tsx examples/boot.ts",
32+
"build": "rslib build && rslib build --config rslib.config.bundle.ts",
33+
"dev": "tsx examples/core/boot.ts",
3434
"test": "vitest run"
3535
},
3636
"dependencies": {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025 Bytedance, Inc. and its affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
// import { pluginReact } from '@rsbuild/plugin-react';
6+
import { defineConfig } from '@rslib/core';
7+
8+
const BANNER = `/**
9+
* Copyright (c) 2025 Bytedance, Inc. and its affiliates.
10+
* SPDX-License-Identifier: Apache-2.0
11+
*/`;
12+
13+
export default defineConfig({
14+
source: {
15+
entry: {
16+
index: 'src/index.ts',
17+
},
18+
decorators: {
19+
version: 'legacy',
20+
},
21+
},
22+
lib: [
23+
{
24+
format: 'umd',
25+
syntax: 'es2021',
26+
bundle: true,
27+
dts: false,
28+
banner: { js: BANNER },
29+
umdName: 'agent_infra_browser_ui',
30+
output: {
31+
minify: true,
32+
externals: ['chromium-bidi/lib/cjs/bidiMapper/BidiMapper.js'],
33+
distPath: {
34+
root: 'dist/bundle/',
35+
},
36+
},
37+
},
38+
],
39+
// performance: {
40+
// bundleAnalyze: {},
41+
// },
42+
output: {
43+
target: 'web',
44+
sourceMap: true,
45+
},
46+
});

packages/browser-ui/rslib.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,5 @@ export default defineConfig({
3939
target: 'web',
4040
cleanDistPath: true,
4141
sourceMap: true,
42-
externals: ['chromium-bidi/lib/cjs/bidiMapper/BidiMapper.js'],
4342
},
4443
});

0 commit comments

Comments
 (0)