Evidence 40.1.8 安装与项目初始化指南

Ubuntu 26.04.1 LTS 服务器实测 Evidence 40.1.8 安装与 DuckDB+PostgreSQL 双数据源报表工程初始化全流程,含脚手架失效与密码注入两条排障实录

EvidenceSQLDuckDBPostgreSQLNode.js2026/11/03

Evidence 40.1.8 安装与项目初始化指南

目标:在一台干净的 Ubuntu 服务器上从 0 到 1 装好开源 CLI @evidence-dev/evidence 40.1.8、初始化报表工程、接入 DuckDB + PostgreSQL 双数据源,并用 dev/build/preview 验证跑通。本文全部命令与回显均在 Ubuntu 26.04.1 LTS 服务器(Node.js v24.22.1 / npm 11.19.1)实测,含脚手架失效与密码注入两条关键排障实录。

一、环境信息

  • 操作系统:Ubuntu 26.04.1 LTS(x86_64)
  • 组件版本:@evidence-dev/evidence 40.1.8(npm registry dist-tags.latest 实查,查询日期 2026-11-03)
  • 数据源:DuckDB(模板自带示例库)+ PostgreSQL 16(监听 127.0.0.1:5433,库名 analytics)
  • 工程目录:/opt/evidence/my-report
  • Evidence 的形态是 Node.js CLI 工具 + 静态站点生成器,没有守护服务:初始化一个项目工程,装依赖,连数据源,evidence dev 起临时预览,evidence build 出静态站。

模板 package.json 声明 "engines": { "node": ">=18.0.0", "npm": ">=7.0.0" }。环境检查实测:

$ node --version
v24.22.1
$ npm --version
11.19.1

二、前置条件

需要 Node.js ≥ 18 与可连的 PostgreSQL 库。本文用 PostgreSQL 16,监听 127.0.0.1:5433,库名 analytics,演示账号 postgres / 密码 q1w2e3r4,灌一张演示表:

$ PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -p 5433 -U postgres -d analytics \
    -c "CREATE TABLE daily_visits (date DATE, page TEXT, visits INTEGER, region TEXT);"

灌数时踩了一个 SQL 本身的坑,留作实录:

ERROR:  function generate_series(timestamp, timestamp, unknown) does not exist

原因是日期序列的第三参写成了整数步长 1(报错回显的第三参类型 unknown 即由此而来);日期序列必须用 interval。修正后按两个页面/地区各插 61 天:

$ PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -p 5433 -U postgres -d analytics \
    -c "INSERT INTO daily_visits SELECT d::date, '/home', (random()*1000)::int, 'cn-east'
    FROM generate_series('2026-09-01'::timestamp, '2026-10-31'::timestamp, interval '1 day') d;"
INSERT 0 61
$ PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -p 5433 -U postgres -d analytics \
    -c "INSERT INTO daily_visits SELECT d::date, '/pricing', (random()*1000)::int, 'cn-north'
    FROM generate_series('2026-09-01'::timestamp, '2026-10-31'::timestamp, interval '1 day') d;"
INSERT 0 61
$ PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -p 5433 -U postgres -d analytics \
    -c "SELECT count(*), min(date), max(date) FROM daily_visits;"
 count |    min     |    max
-------+------------+------------
   122 | 2026-09-01 | 2026-10-31

三、版本选型说明:npx create 已失效,用官方模板仓库

3.1 排障实录一:npm init evidence 与 npx evidence create 都不可用

老文档里的 npx evidence@latest create 在 2026-11 实测走不通,逐条证据:

  • npm 上名为 evidence 的包(1.0.3,2015 年发布)与 Evidence 无关,npx evidence 会装错包;
  • npm init evidence 对应的初始化包 create-evidence 最新版 0.0.1(2024-08-22),解包核对 bin/cli.js 与 @evidence-dev/evidence@40.1.8 的 CLI 完全相同——只有 dev/build/sources/preview,没有 create 子命令;
  • 历史上的 CLI 包 @evidence-dev/cli 已从 npm 下架(registry 返回 404 '@evidence-dev/cli' is not in this registry)。

因此 40.1.8 的项目初始化只能从官方模板仓库取工程,下文给出两种取法。

3.2 版本口径

@evidence-dev/evidence 最新稳定版 40.1.8 即开源 CLI 的末代稳定版(2026 年官方主线转向 Evidence Studio 与新 CLI,背景见 《Evidence 40.1.8 介绍与选型指南》),工程内以 package.json 钉住 ^40.1.8、package-lock.json 锁死依赖树保证可复现。

四、安装方案 A:git 钉住开源版模板提交(本文主路径)

官方模板仓库 evidence-dev/template 的 main 分支已于 2026-10-30 改为「Deprecated」告示页(指向新 CLI),最后一个开源版模板提交是 4b13d42e15(2026-02-06,package.json 依赖 @evidence-dev/evidence: ^40.1.8)。主项目用 git 钉住该提交拉取(实测):

$ git clone https://github.com/evidence-dev/template.git my-report
$ cd my-report
$ git checkout 4b13d42e15

装依赖(模板自带 package-lock.json,用 npm ci 保证可复现):

$ cd my-report && npm ci
added 1311 packages in 18s

4.1 项目结构

my-report/
├── evidence.config.yaml        # 全局配置:主题/外观/插件声明
├── package.json                # scripts 封装 evidence 子命令
├── pages/                      # 报表页面(Markdown + ```sql 块)
│   ├── index.md
│   └── about.md
├── sources/
│   └── needful_things/         # 一个数据源 = 一个目录
│       ├── connection.yaml     # 源连接配置
│       ├── orders.sql          # 一条查询 = 一个 .sql 文件
│       └── needful_things.duckdb  # DuckDB 本地库文件
└── static/                     # 静态资源(图标等)

注意:模板没有 svelte.config.js / vite.config.js(实测 cat 报 No such file),SvelteKit/Vite 配置由 CLI 内置生成到隐藏工作区 .evidence/,日常不需要碰。

五、安装方案 B:degit 拉取(不留 Git 历史)

不想留 Git 历史的可用 degit(实测回显如下,末行目录名即所选目标目录):

$ npx degit evidence-dev/template#4b13d42e15 degit-test
> cloned evidence-dev/template#4b13d42e15 to degit-test
! action wants to remove .github but it does not exist
> removed: .devcontainer/, scripts/

后续 npm ci 与方案 A 相同。

六、方案对比与选择建议

维度方案 A(git clone + checkout)方案 B(degit)
取到的内容模板全仓 + 钉住历史提交仅该提交的快照文件
.git 目录有(可再切其他提交)无
依赖gitnpx(自动装 degit)
适用长期演进工程、需回溯模板变更一次性起步、嫌 .git 碍事

两方案取到的是同一个开源版模板提交 4b13d42e15,工程内容一致;内网无法访问 GitHub 时,可在可联网机器上按任一方案打包工程再拷贝(离线交付后 npm ci 需本地 npm 缓存或私有 npm registry)。

七、DuckDB 数据源(模板自带)

模板预置了示例源 needful_things,sources/needful_things/connection.yaml 实测原文:

sources:
  - name: needful_things
    type: duckdb
    options:
      filepath: ./needful_things.duckdb

同目录 orders.sql 内容就是 select * from orders。示例库含一张 10000 行的 orders 表(列:id、order_datetime、order_month、first_name、last_name、email、address、state、zipcode、item、category、sales、channel、channel_group、channel_month)。

首次执行 evidence sources 前,先跑一次会看到全部查询物化:

$ npx evidence sources
- Loading plugins & sources
✔ Loading plugins & sources
-----
  [Processing] needful_things
- Processing...
  needful_things ⚠ No results returned.
- Processing...
  orders ✔ Finished, wrote 10000 rows.
-----
[INFO]:    Evaluated sources, saving manifest
[INFO]:    ✅ Done!

⚠ No results returned. 是目录级占位提示,非错误。产物落在 .evidence/template/static/data/needful_things/orders/orders.parquet(目录可由 EVIDENCE_DATA_DIR 改,见 《Evidence 40.1.8 配置参数详解》 第七节)。

八、接入 PostgreSQL 源

8.1 建源目录

sources/web_analytics/connection.yaml:

name: web_analytics
type: postgres
options:
  host: 127.0.0.1
  port: 5433
  database: analytics
  user: postgres
  ssl: null
  timeout: 180000

sources/web_analytics/daily_visits.sql:

select * from daily_visits

8.2 排障实录二:密码注入的三次试错

第一次:按旧文档惯例在 connection.yaml 写 password: ${ENV_POSTGRES_PASSWORD}、.env 写 ENV_POSTGRES_PASSWORD=q1w2e3r4,执行 evidence sources 报错:

  daily_visits ✖ Error: password authentication failed for user "postgres"

第二次:改 password: ${POSTGRES_PASSWORD} 并在 .env 写 EVIDENCE_VAR__POSTGRES_PASSWORD=q1w2e3r4,同样报 password authentication failed——查 SDK 源码确认 EVIDENCE_VAR__<变量> 只作用于 SQL 查询文件里的 ${} 替换,connection.yaml 的 options 不做任何 ${} 插值,占位符被当字面量发给了数据库。

第三次(正确姿势):connection.yaml 里删掉 password 行,凭据改用环境变量 EVIDENCE_SOURCE__<源名>__<选项名> 注入,.env:

EVIDENCE_SOURCE__web_analytics__password=q1w2e3r4

重跑即成功:

$ npx evidence sources
-----
  [Processing] needful_things
- Processing...
  orders ✔ Finished, wrote 10000 rows.
-----
  [Processing] web_analytics
- Processing...
  daily_visits ✔ Finished, wrote 122 rows.
-----
[INFO]:    Evaluated sources, saving manifest
[INFO]:    ✅ Done!

密码机制完整规则(含 base64 的 connection.options.yaml、.env 只加载 EVIDENCE_/VITE_ 前缀)见 《Evidence 40.1.8 配置参数详解》 第六节。

九、启动 dev 服务器实测

$ npx evidence dev --port 8137

  VITE  v5.4.21   ready in 2057  ms

  ➜  Local:   http://localhost:8137/
  ➜  Network: use --host to expose

说明两点:evidence dev 底层就是 vite dev --port 3000(CLI 源码硬编码默认 3000),追加的参数原样透传给 Vite,后出现的 --port 覆盖默认值;需要局域网可访问时加 --host 0.0.0.0。

页面验证(含本文第八节的 Postgres 源数据页,见下节):

$ curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8137/
200
$ curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8137/visits/
200

dev 服务器改页面即时热更,Ctrl+C 即停,无常驻进程。

十、第一页报表:双源混排 + 构建静态站

新建 pages/visits.md,同一页面混用 Postgres 与 DuckDB 两个源的查询和三类组件:

---
title: Daily Visits
---

```sql daily
  select date, sum(visits) as visits
  from web_analytics.daily_visits
  group by date order by date
  select category, sum(sales) as revenue
  from needful_things.orders
  group by category order by revenue desc limit 5
<LineChart data={daily} x=date y=visits title="Daily visits (Postgres)" /> <BarChart data={top_category} x=category y=revenue title="Order revenue by category" /> ```

构建静态站:

$ npx evidence build
...(vite 编译输出,节选)
> Using @sveltejs/adapter-static
  Wrote site to "./build"
  ✔ done
Build complete --> ./build

实测产物 build/ 目录 87M(含全部 parquet 数据与浏览器端 DuckDB-WASM 运行时),build/visits/index.html 已预渲染。本地验证产物:

$ npx evidence preview --listen 8138
 INFO  Accepting connections at http://localhost:8138

浏览器打开 http://localhost:8138/visits/ 即可看到折线图与柱状图——此时服务的是纯静态文件,查询在浏览器内对 parquet 快照执行。

构建期踩过的第三个坑(排障):凭直觉把 SQL 写成 sum(order_total),构建报:

[!ERROR] Binder Error: Referenced column "order_total" not found.
LINE 4:          sum(order_total) as revenue

错误信息会列出候选列名(order_datetime、order_month、zipcode、channel_group、channel_month),据此核对真实表结构后改为 sum(sales) 通过。教训:SQL 里引用源表列前先 DESCRIBE 确认真实列名,别照抄文档示例字段。

十一、配置说明

工程配置分散在四类载体,逐项详解见 《Evidence 40.1.8 配置参数详解》:

  • evidence.config.yaml:外观 appearance、主题色板 theme、组件/数据源插件声明 plugins;
  • sources/<源名>/connection.yaml:数据源连接参数(敏感值不落此文件,走环境变量注入);
  • .env:EVIDENCE_/VITE_ 前缀白名单加载,凭据用 EVIDENCE_SOURCE__<源名>__<选项名>;
  • pages/*.md 组件属性:图表/表格级配置。

十二、常见问题(FAQ)

Q1: npm init evidence / npx evidence create 起不了项目? A: 脚手架已失效(见 3.1 实录),用本文第四/五节从模板仓库取工程。

Q2: connection.yaml 写了 password: ${...} 仍报 password authentication failed? A: connection.yaml 的值域不做 ${} 插值(8.2 实录二),删掉 password 行,改用 .env 中 EVIDENCE_SOURCE__<源名>__password 注入。

Q3: 构建报 Binder Error: Referenced column ... not found? A: SQL 引用了源表不存在的列(第十节实录),按报错列出的候选列名核对真实表结构后改正。

十三、收尾:卸载与清理

Evidence 项目无系统级安装:删除项目目录即卸载;.env 含凭据,随目录一并清理;构建中间产物在 .evidence/、build/、.svelte-kit/,可安全删除。dev/preview 服务器为前台进程,Ctrl+C 退出,无残留服务。

十四、参考链接

Evidence 40.1.8 安装与项目初始化指南 - Quzuo