Files
AFFiNE-Mirror/docs/BUILDING.md
T

10 KiB

Building AFFiNE Web

Warning

This document is not guaranteed to be up-to-date. If you find any outdated information, please feel free to open an issue or submit a PR.

Note This guide covers building and developing the web app. For the desktop client app, see building-desktop-client-app.md. For running the server (cloud features) locally, see developing-server.md.

Table of Contents

Sign the CLA first

AFFiNE requires every contributor to sign the Contributor License Agreement before a pull request can be merged. The license/cla status check on your PR stays red — and blocks the merge — until every committer on the PR has signed. Signing takes less than a minute, so do it before (or right after) opening your first PR:

  1. Open https://cla-assistant.io/toeverything/AFFiNE.
  2. Sign in with your GitHub account and agree.

If you opened your PR before signing, the CLA-assistant bot will have left a comment on it with a signing link. After signing, click the recheck link in that same comment (or push a new commit) to refresh the check.

If license/cla is still red after you signed:

  • Every committer must sign. The bot's comment lists each commit author in the PR — every name marked with still needs to sign, including co-authors.
  • Your commit email must be linked to your GitHub account. CLA assistant matches commits to GitHub users by the commit author email. Run git log --format='%an %ae' and make sure those emails appear in your GitHub email settings. Otherwise, either add the email to GitHub, or rewrite the commits with the correct identity and force-push.

Prerequisites

AFFiNE client has both Node.js & Rust toolchains.

Node.js

Develop with the Node.js version pinned in .nvmrc (currently Node.js 22; package.json requires >=22.12.0 <23.0.0).

The easiest way is a version manager that reads .nvmrc:

# with fnm (https://github.com/Schniz/fnm)
fnm use --install-if-missing

# or with nvm (https://github.com/nvm-sh/nvm)
nvm install && nvm use

Alternatively, install Node.js 22 (LTS) manually from https://nodejs.org/en/download.

Yarn

We use modern Yarn (currently 4.x, pinned by the packageManager field in package.json). Yarn 1 will not work. Enable it via Corepack, which ships with Node.js:

corepack enable

After this, yarn inside the repository automatically resolves to the pinned version — verify with yarn -v (it should print 4.x, not 1.x).

Rust

Install the Rust toolchain via rustup. The required version is pinned in rust-toolchain.toml, and rustup installs it automatically the first time you build inside the repository.

Setup Environment

Clone the repository

Linux & macOS

git clone https://github.com/toeverything/AFFiNE
cd AFFiNE

Windows

In our codebase, we use symbolic links. Due to the security design of Windows, the creation of symbolic links requires administrator privileges. This is part of the security policy settings of Windows, and more information can be found at Security Policy Settings for Creating Symbolic Links.

For detailed guidance on enabling this feature, please refer to the official documentation: Enable Developer Mode on Windows.

Once Developer Mode is enabled, execute the following command with administrator privileges:

# Enable symbolic links
git config --global core.symlinks true
# Clone the repository
git clone https://github.com/toeverything/AFFiNE

Install dependencies

yarn install

This also initializes the workspace (yarn affine init) and installs the git hooks through the postinstall script.

Build Native Dependencies

Run the following script. It will build the native module at packages/frontend/native and build Node.js binding using NAPI.rs. This could take a while if you build it for the first time.

yarn affine @affine/native build

Note: use strip from system instead of binutils if you are running macOS. See problem here

Build Server Dependencies

Only needed if you plan to run the local server (cloud features) or the cloud E2E suites:

yarn affine @affine/server-native build

Start Development Server

yarn dev

You will be prompted to choose which package to run — pick @affine/web for the web app, then open http://localhost:8080.

You can skip the prompt with the -p (--package) flag:

yarn dev -p @affine/web

Other dev targets include @affine/server, @affine/electron, @affine/mobile, @affine/admin, @affine/ios and @affine/android.

Running @affine/web alone is enough for most editor and UI work — workspaces are stored locally in the browser. To work on cloud features (accounts, sync, collaboration, AI), run the local server as well: follow developing-server.md.

Testing

Adding test cases is strongly encouraged when you contribute new features and bug fixes.

We use Vitest for unit tests and Playwright for E2E tests.

Unit Test

yarn test

E2E Test

Install the browser binaries once before the first run:

npx playwright install

The E2E suites live in tests:

Suite Run with Notes
affine-local yarn workspace @affine-test/affine-local e2e Web app, no server needed
affine-cloud yarn workspace @affine-test/affine-cloud e2e Requires the local server
affine-cloud-copilot yarn workspace @affine-test/affine-cloud-copilot e2e Requires the local server
affine-desktop yarn workspace @affine-test/affine-desktop e2e Desktop (Electron) app
affine-desktop-cloud yarn workspace @affine-test/affine-desktop-cloud e2e Desktop + local server
affine-mobile yarn workspace @affine-test/affine-mobile e2e Mobile UI

There is also @affine-test/blocksuite (yarn workspace @affine-test/blocksuite test) for BlockSuite integration tests.

Linting and Type Checking

CI runs these checks on every PR — running them locally first saves you a review round trip:

# lint (oxlint) + format check (oxfmt)
yarn lint

# auto-fix lint & format issues
yarn lint:fix

# TypeScript type check
yarn typecheck

Submitting a Pull Request

  1. Make sure you have signed the CLA.

  2. Fork the repository and create your branch from canary (the default development branch).

  3. Make your changes. Add or update tests where it makes sense, and run yarn lint, yarn typecheck and the relevant test suites locally.

  4. Open the PR against the canary branch of toeverything/AFFiNE.

  5. Give the PR a title that follows Conventional Commits — this is enforced by the PR Title Lint CI check:

    type(scope): short description
    
    # examples
    fix(editor): keep text selection after paste
    feat(core): add custom icons for folders
    docs: update building guide
    
    • Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
    • Scopes (optional; if present, must be one of): admin, electron, server, core, web, mobile, ios, android, mobile-native, docs, component, env, graphql, hooks, i18n, native, templates, debug, nbstore, infra, editor, tools, y-octo, client
  6. Your PR can be merged once:

    • the license/cla check is green — every committer has signed the CLA;
    • CI passes — build & tests, PR title lint;
    • a maintainer has reviewed and approved it. Reviewers are assigned automatically, and an automated reviewer may also leave comments — please address or answer them.

Troubleshooting

  • yarn install fails or complains about the Node/Yarn version — check that node -v matches .nvmrc (fnm use / nvm use) and that Corepack is enabled (yarn -v should print 4.x, not 1.x).
  • Native module fails to build on macOS — make sure strip is the system one, not the one from binutils (details).
  • EPERM: operation not permitted, symlink on Windows — enable Developer Mode and symlinks before cloning; see Windows.
  • App fails to start after pulling the latest canary — dependencies or Rust bindings may have changed: re-run yarn install and yarn affine @affine/native build.
  • Playwright can't find browsers — run npx playwright install.
  • The license/cla check stays red — see Sign the CLA first.