Skip to content

Commit c6d01ed

Browse files
author
宏旭
committed
feat(ev): add browser-to-terminal logging
1 parent ba3049e commit c6d01ed

13 files changed

Lines changed: 253 additions & 8 deletions

File tree

docs/docs/config.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ page-plugin settings.
2121
| `routing` | Enable file-based pages and select SPA or MPA | Not enabled until declared |
2222
| `conventions` | Enable all framework file conventions | `true` |
2323
| `dev` | Browser development server | Port `3000` |
24+
| `logging` | Development logging, including browser-to-terminal forwarding | Browser errors forwarded |
2425
| `server` | Server runtime, build resolution, and development server | Base path `/__evjs`, dev port `3001` |
2526
| `transport` | Browser-to-server origin | Same origin |
2627
| `target` | Production Android and iOS compatibility target | Bundler default |
@@ -129,6 +130,22 @@ A proxy rule accepts `context`, `target`, optional `pathRewrite`,
129130
client HTTPS. Select the Webpack adapter when the client dev server requires a
130131
custom key/certificate pair.
131132

133+
### `logging`
134+
135+
`logging.browserToTerminal` follows the Next.js-compatible level contract and
136+
only affects `ev dev` with the Utoopack adapter:
137+
138+
| Value | Browser output forwarded to the terminal |
139+
| --- | --- |
140+
| `"error"` | Errors and unhandled rejections (default) |
141+
| `"warn"` | Warnings plus errors |
142+
| `true` | All standard console levels |
143+
| `false` | Nothing |
144+
145+
Set top-level `logging: false` to disable configurable logging. Essential CLI
146+
lifecycle output and fatal diagnostics remain enabled. The Webpack adapter does
147+
not currently implement browser log forwarding.
148+
132149
### `server.dev`
133150

134151
| Field | Type | Default |

docs/docs/dev.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ the same project directory at a time; stop an existing `dev`, `prepare`, or
4242
import { defineConfig } from "@evjs/ev";
4343

4444
export default defineConfig({
45+
logging: {
46+
browserToTerminal: "error", // Browser errors -> terminal (default)
47+
},
4548
dev: {
4649
port: 4000,
4750
},
@@ -172,6 +175,25 @@ evjs core does not reserve shortcut keys; installed plugins define the keys
172175
they use. Plugin authors can find the authoring contract in
173176
[Plugin Hooks](./plugin-hooks).
174177

178+
## Browser logs in the terminal
179+
180+
The Utoopack development server forwards browser errors to the terminal by
181+
default. Configure the Next.js-compatible forwarding level in `ev.config.ts`:
182+
183+
```ts
184+
export default defineConfig({
185+
logging: {
186+
browserToTerminal: "warn",
187+
},
188+
});
189+
```
190+
191+
Use `"error"` for errors only (the default), `"warn"` for warnings and errors,
192+
`true` for all standard console levels, or `false` to disable forwarding.
193+
Forwarded lines use a `[browser]` prefix and include source-mapped application
194+
locations when available. This is development-only and is not a production log
195+
collector. The Webpack adapter does not currently implement this option.
196+
175197
## Test server paths directly
176198

177199
The default server runtime prefix is `/__evjs`. Server-function, PPR, and RSC

docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/config.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default defineConfig({
1919
| `routing` | 启用文件页面并选择 SPA 或 MPA | 声明后才启用 |
2020
| `conventions` | 启用全部框架文件约定 | `true` |
2121
| `dev` | 浏览器开发服务器 | 端口 `3000` |
22+
| `logging` | 开发日志,包括浏览器到终端转发 | 默认转发浏览器错误 |
2223
| `server` | 服务端运行时、构建解析与开发服务器 | 基础路径 `/__evjs`,开发端口 `3001` |
2324
| `transport` | 浏览器到服务端的来源 | 同源 |
2425
| `target` | 生产 Android 与 iOS 兼容目标 | 构建器默认值 |
@@ -121,6 +122,20 @@ export default defineConfig({
121122

122123
代理规则支持 `context``target`,以及可选 `pathRewrite``changeOrigin``secure`。默认 Utoopack 适配器支持布尔形式的客户端 HTTPS;需要自定义客户端证书时选择 Webpack 适配器。
123124

125+
### `logging`
126+
127+
`logging.browserToTerminal` 使用与 Next.js 兼容的级别契约,仅影响采用
128+
Utoopack 适配器的 `ev dev`
129+
130+
|| 转发到终端的浏览器输出 |
131+
| --- | --- |
132+
| `"error"` | 错误与未处理的 Promise rejection(默认值) |
133+
| `"warn"` | 警告与错误 |
134+
| `true` | 全部标准 console 级别 |
135+
| `false` | 不转发 |
136+
137+
设置顶层 `logging: false` 可关闭可配置日志。必要的 CLI 生命周期输出与致命诊断仍会保留。Webpack 适配器目前尚未实现浏览器日志转发。
138+
124139
### `server.dev`
125140

126141
| 字段 | 类型 | 默认值 |

docs/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dev.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ flowchart LR
3737
import { defineConfig } from "@evjs/ev";
3838

3939
export default defineConfig({
40+
logging: {
41+
browserToTerminal: "error", // 浏览器错误 -> 终端(默认值)
42+
},
4043
dev: {
4144
port: 4000,
4245
},
@@ -150,6 +153,20 @@ ev dev --no-shortcuts
150153

151154
evjs 核心不占用任何按键,具体快捷键由已安装插件定义。插件作者可以在[插件生命周期钩子](./plugin-hooks)查看契约。
152155

156+
## 在终端查看浏览器日志
157+
158+
Utoopack 开发服务器默认会将浏览器错误转发到终端。在 `ev.config.ts` 中使用与 Next.js 兼容的选项配置转发级别:
159+
160+
```ts
161+
export default defineConfig({
162+
logging: {
163+
browserToTerminal: "warn",
164+
},
165+
});
166+
```
167+
168+
`"error"` 仅转发错误(默认值),`"warn"` 转发警告与错误,`true` 转发全部标准 console 级别,`false` 关闭转发。转发行以 `[browser]` 为前缀,并在可用时包含 source map 还原后的应用源码位置。该能力仅用于开发,并非生产日志采集器。Webpack 适配器目前尚未实现此选项。
169+
153170
## 直接测试服务端路径
154171

155172
默认服务端运行时前缀是 `/__evjs`。只有应用使用对应能力时才会创建服务端函数、PPR 与 RSC 路径。这个前缀不是服务端通配命名空间,因此无关客户端路由仍然可用。

packages/bundler-utoopack/src/adapter/config/create-config.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
resolveBuildOutputPaths,
2121
SERVER_FUNCTION_TRANSFORM_RUNTIME,
2222
} from "@evjs/ev/_internal/build";
23-
import type { ResolvedConfig } from "@evjs/ev/config";
23+
import type { BrowserToTerminal, ResolvedConfig } from "@evjs/ev/config";
2424
import type { ConfigureBundlerContext, PluginHooks } from "@evjs/ev/plugin";
2525
import { pageRoutePathToRegExp } from "@evjs/shared";
2626
import type { BuildPlan } from "@evjs/shared/manifest";
@@ -41,6 +41,12 @@ const lessImplementation = require.resolve("less");
4141
const lessLoader = require.resolve("less-loader");
4242
const spaHistoryFallbackRuleIndexes = new WeakMap<ConfigComplete, number>();
4343

44+
type UtoopackDevServerConfigWithBrowserLogs = NonNullable<
45+
ConfigComplete["devServer"]
46+
> & {
47+
browserToTerminal?: BrowserToTerminal;
48+
};
49+
4450
export function getSpaHistoryFallbackRuleIndex(
4551
config: ConfigComplete,
4652
): number | undefined {
@@ -118,6 +124,16 @@ export async function createUtoopackConfig(
118124
const outputPaths = resolveBuildOutputPaths(cwd, plan);
119125
await assertSafeBuildOutputPaths(cwd, outputPaths);
120126

127+
const devServerConfig: UtoopackDevServerConfigWithBrowserLogs = {
128+
hot: true,
129+
port: config.dev.port,
130+
https: config.dev.https !== false,
131+
proxy: devProxy,
132+
...(!isProduction
133+
? { browserToTerminal: config.logging.browserToTerminal }
134+
: {}),
135+
};
136+
121137
const utoopackConfig: ConfigComplete = {
122138
mode,
123139
...(isProduction && config.target !== undefined && clientEntries.length > 0
@@ -209,12 +225,7 @@ export async function createUtoopackConfig(
209225
: {}),
210226

211227
// Dev server configuration
212-
devServer: {
213-
hot: true,
214-
port: config.dev.port,
215-
https: config.dev.https !== false,
216-
proxy: devProxy,
217-
},
228+
devServer: devServerConfig,
218229
};
219230
const frameworkExpectation =
220231
snapshotUtoopackFrameworkExpectation(utoopackConfig);

packages/bundler-utoopack/tests/adapter.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type { ConfigComplete } from "@utoo/pack";
2424
import { afterEach, describe, expect, it, vi } from "vitest";
2525
import { withPageRoutingDefaults } from "../../ev/esm/_internal/build/discovery/convention-config.js";
2626
import { createClientRuntime } from "../../ev/src/_internal/build/output/framework-runtime.js";
27+
import { createUtoopackConfig } from "../src/adapter/config/create-config.js";
2728
import {
2829
utoopackAdapter,
2930
__testing as utoopackAdapterTesting,
@@ -471,6 +472,33 @@ describe("utoopackAdapter output safety", () => {
471472
});
472473
});
473474

475+
describe("utoopackAdapter browser log forwarding config", () => {
476+
it("maps the resolved level into development config only", async () => {
477+
const cwd = await makeProject();
478+
const config = await resolveProjectConfig(cwd, {
479+
logging: { browserToTerminal: "warn" },
480+
});
481+
const { plan } = await createBuildContext(config, cwd);
482+
483+
const development = await createUtoopackConfig(config, plan, cwd, []);
484+
expect(Reflect.get(development.devServer ?? {}, "browserToTerminal")).toBe(
485+
"warn",
486+
);
487+
488+
const productionPlan = structuredClone(plan);
489+
productionPlan.mode = "production";
490+
const production = await createUtoopackConfig(
491+
config,
492+
productionPlan,
493+
cwd,
494+
[],
495+
);
496+
expect(Object.hasOwn(production.devServer ?? {}, "browserToTerminal")).toBe(
497+
false,
498+
);
499+
});
500+
});
501+
474502
describe("utoopackAdapter dev", () => {
475503
it("waits for readable stats until the session is aborted", async () => {
476504
const cwd = await makeProject();

packages/bundler-utoopack/tests/create-config.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ describe("createUtoopackConfig", () => {
4747
proxy: [],
4848
cliShortcuts: true,
4949
},
50+
logging: {
51+
browserToTerminal: "error",
52+
},
5053
server: {
5154
basePath: "/__evjs",
5255
runtime: {

packages/bundler-utoopack/tests/multi-server-entry.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ function createResolvedConfig(): Parameters<typeof createUtoopackConfig>[0] {
141141
proxy: [],
142142
cliShortcuts: true,
143143
},
144+
logging: {
145+
browserToTerminal: "error",
146+
},
144147
server: {
145148
basePath: "/__evjs",
146149
runtime: {

packages/bundler-webpack/tests/create-config.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,9 @@ function createResolvedConfig(
12221222
proxy: [],
12231223
cliShortcuts: true,
12241224
},
1225+
logging: {
1226+
browserToTerminal: "error",
1227+
},
12251228
output: {
12261229
client: "dist/client",
12271230
server: "dist/server",

packages/cli/tests/config.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ describe("CONFIG_DEFAULTS", () => {
4646
expect(CONFIG_DEFAULTS.serverPort).toBe(3001);
4747
expect(CONFIG_DEFAULTS.serverBasePath).toBe("/__evjs");
4848
expect(CONFIG_DEFAULTS.crossOriginLoading).toBe("anonymous");
49+
expect(CONFIG_DEFAULTS.browserToTerminal).toBe("error");
4950
});
5051

5152
it("is readonly", () => {
@@ -61,6 +62,7 @@ describe("CONFIG_DEFAULTS", () => {
6162
outputServerDir: "dist/server",
6263
pageRoot: "./src/pages",
6364
mount: "#app",
65+
browserToTerminal: "error",
6466
});
6567
});
6668
});

0 commit comments

Comments
 (0)