mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-26 04:24:23 +03:00
chore: add monorepo tools (#9196)
This commit is contained in:
parent
e3a8b63e38
commit
2443935830
@ -9,7 +9,7 @@ corepack prepare yarn@stable --activate
|
||||
yarn install
|
||||
|
||||
# Build Server Dependencies
|
||||
yarn workspace @affine/server-native build
|
||||
yarn affine @affine/server-native build
|
||||
|
||||
# Create database
|
||||
yarn workspace @affine/server prisma db push
|
||||
yarn affine @affine/server prisma db push
|
||||
|
@ -21,6 +21,5 @@
|
||||
}
|
||||
},
|
||||
"updateContentCommand": "bash ./.devcontainer/build.sh",
|
||||
"postCreateCommand": "bash ./.devcontainer/setup-user.sh",
|
||||
"postStartCommand": ["yarn dev", "yarn workspace @affine/server dev"]
|
||||
"postCreateCommand": "bash ./.devcontainer/setup-user.sh"
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
CHANGELOG_URL=
|
||||
ENABLE_NEW_SETTING_UNSTABLE_API=
|
||||
ENABLE_CAPTCHA=
|
||||
CAPTCHA_SITE_KEY=
|
||||
ENABLE_ENHANCE_SHARE_MODE=
|
||||
ALLOW_LOCAL_WORKSPACE=
|
||||
DEBUG_JOTAI=
|
2
.github/actions/copilot-test/action.yml
vendored
2
.github/actions/copilot-test/action.yml
vendored
@ -3,7 +3,7 @@ description: 'Run Copilot E2E Test'
|
||||
inputs:
|
||||
script:
|
||||
description: 'Script to run'
|
||||
default: 'yarn workspace @affine-test/affine-cloud-copilot e2e --forbid-only'
|
||||
default: 'yarn affine @affine-test/affine-cloud-copilot e2e --forbid-only'
|
||||
required: false
|
||||
openai-key:
|
||||
description: 'OpenAI secret key'
|
||||
|
6
.github/actions/server-test-env/action.yml
vendored
6
.github/actions/server-test-env/action.yml
vendored
@ -18,6 +18,6 @@ runs:
|
||||
env:
|
||||
NODE_ENV: test
|
||||
run: |
|
||||
yarn workspace @affine/server exec prisma generate
|
||||
yarn workspace @affine/server exec prisma db push
|
||||
yarn workspace @affine/server data-migration run
|
||||
yarn affine @affine/server prisma generate
|
||||
yarn affine @affine/server prisma db push
|
||||
yarn affine @affine/server data-migration run
|
||||
|
10
.github/workflows/build-images.yml
vendored
10
.github/workflows/build-images.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
electron-install: false
|
||||
extra-flags: workspaces focus @affine/server
|
||||
- name: Build Server
|
||||
run: yarn workspace @affine/server build
|
||||
run: yarn affine @affine/server build
|
||||
- name: Upload server dist
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@ -47,7 +47,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Build Core
|
||||
run: yarn workspace @affine/web build
|
||||
run: yarn affine @affine/web build
|
||||
env:
|
||||
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Build Admin
|
||||
run: yarn workspace @affine/admin build
|
||||
run: yarn affine @affine/admin build
|
||||
env:
|
||||
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
@ -112,7 +112,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Build Mobile
|
||||
run: yarn workspace @affine/mobile build
|
||||
run: yarn affine @affine/mobile build
|
||||
env:
|
||||
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
@ -257,7 +257,7 @@ jobs:
|
||||
yarn workspaces focus @affine/server --production
|
||||
|
||||
- name: Generate Prisma client
|
||||
run: yarn workspace @affine/server prisma generate
|
||||
run: yarn affine @affine/server prisma generate
|
||||
|
||||
- name: Setup Version
|
||||
id: version
|
||||
|
39
.github/workflows/build-test.yml
vendored
39
.github/workflows/build-test.yml
vendored
@ -89,7 +89,7 @@ jobs:
|
||||
electron-install: false
|
||||
full-cache: true
|
||||
- name: Run i18n codegen
|
||||
run: yarn workspace @affine/i18n build
|
||||
run: yarn affine @affine/i18n build
|
||||
- name: Run ESLint
|
||||
run: yarn lint:eslint --max-warnings=0
|
||||
- name: Run Prettier
|
||||
@ -162,7 +162,7 @@ jobs:
|
||||
full-cache: true
|
||||
|
||||
- name: Run playwright tests
|
||||
run: yarn workspace @affine-test/affine-local e2e --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
||||
run: yarn affine @affine-test/affine-local e2e --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
||||
|
||||
- name: Upload test results
|
||||
if: ${{ failure() }}
|
||||
@ -192,7 +192,7 @@ jobs:
|
||||
full-cache: true
|
||||
|
||||
- name: Run playwright tests
|
||||
run: yarn workspace @affine-test/affine-mobile e2e --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
||||
run: yarn affine @affine-test/affine-mobile e2e --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
||||
|
||||
- name: Upload test results
|
||||
if: ${{ failure() }}
|
||||
@ -315,8 +315,7 @@ jobs:
|
||||
electron-install: false
|
||||
full-cache: true
|
||||
- name: Build Electron renderer
|
||||
# always skip cache because its fast, and cache configuration is always changing
|
||||
run: yarn build
|
||||
run: yarn affine @affine/electron bundle
|
||||
env:
|
||||
DISTRIBUTION: desktop
|
||||
- name: zip web
|
||||
@ -377,7 +376,7 @@ jobs:
|
||||
uses: ./.github/actions/server-test-env
|
||||
|
||||
- name: Run server tests
|
||||
run: yarn workspace @affine/server test:coverage
|
||||
run: yarn affine @affine/server test:coverage
|
||||
env:
|
||||
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
|
||||
COPILOT_OPENAI_API_KEY: 'use_fake_openai_api_key'
|
||||
@ -480,7 +479,7 @@ jobs:
|
||||
|
||||
- name: Run server tests
|
||||
if: ${{ steps.check-blocksuite-update.outputs.skip != 'true' || steps.apifilter.outputs.changed == 'true' }}
|
||||
run: yarn workspace @affine/server test:copilot:coverage --forbid-only
|
||||
run: yarn affine @affine/server test:copilot:coverage --forbid-only
|
||||
env:
|
||||
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
|
||||
COPILOT_OPENAI_API_KEY: ${{ secrets.COPILOT_OPENAI_API_KEY }}
|
||||
@ -570,7 +569,7 @@ jobs:
|
||||
if: ${{ steps.check-blocksuite-update.outputs.skip != 'true' || steps.e2efilter.outputs.changed == 'true' }}
|
||||
uses: ./.github/actions/copilot-test
|
||||
with:
|
||||
script: yarn workspace @affine-test/affine-cloud-copilot e2e --forbid-only --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||
script: yarn affine @affine-test/affine-cloud-copilot e2e --forbid-only --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||
openai-key: ${{ secrets.COPILOT_OPENAI_API_KEY }}
|
||||
fal-key: ${{ secrets.COPILOT_FAL_API_KEY }}
|
||||
|
||||
@ -587,19 +586,19 @@ jobs:
|
||||
matrix:
|
||||
tests:
|
||||
- name: 'Server E2E Test 1/3'
|
||||
script: yarn workspace @affine-test/affine-cloud e2e --forbid-only --shard=1/3
|
||||
script: yarn affine @affine-test/affine-cloud e2e --forbid-only --shard=1/3
|
||||
- name: 'Server E2E Test 2/3'
|
||||
script: yarn workspace @affine-test/affine-cloud e2e --forbid-only --shard=2/3
|
||||
script: yarn affine @affine-test/affine-cloud e2e --forbid-only --shard=2/3
|
||||
- name: 'Server E2E Test 3/3'
|
||||
script: yarn workspace @affine-test/affine-cloud e2e --forbid-only --shard=3/3
|
||||
script: yarn affine @affine-test/affine-cloud e2e --forbid-only --shard=3/3
|
||||
- name: 'Server Desktop E2E Test'
|
||||
script: |
|
||||
yarn workspace @affine/electron build:dev
|
||||
yarn affine @affine/electron build:dev
|
||||
# Workaround for Electron apps failing to initialize on Ubuntu 24.04 due to AppArmor restrictions
|
||||
# Disables unprivileged user namespaces restriction to allow Electron apps to run
|
||||
# Reference: https://github.com/electron/electron/issues/42510
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn workspace @affine-test/affine-desktop-cloud e2e
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn affine @affine-test/affine-desktop-cloud e2e
|
||||
needs:
|
||||
- build-server-native
|
||||
- build-native
|
||||
@ -729,7 +728,7 @@ jobs:
|
||||
- name: Run unit tests
|
||||
if: ${{ matrix.spec.test }}
|
||||
shell: bash
|
||||
run: yarn workspace @affine/electron vitest
|
||||
run: yarn affine @affine/electron vitest
|
||||
|
||||
- name: Download web artifact
|
||||
uses: ./.github/actions/download-web
|
||||
@ -737,7 +736,7 @@ jobs:
|
||||
path: packages/frontend/apps/electron/resources/web-static
|
||||
|
||||
- name: Build Desktop Layers
|
||||
run: yarn workspace @affine/electron build
|
||||
run: yarn affine @affine/electron build
|
||||
|
||||
- name: Run desktop tests
|
||||
if: ${{ matrix.spec.os == 'ubuntu-latest' }}
|
||||
@ -746,11 +745,11 @@ jobs:
|
||||
# Disables unprivileged user namespaces restriction to allow Electron apps to run
|
||||
# Reference: https://github.com/electron/electron/issues/42510
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn workspace @affine-test/affine-desktop e2e
|
||||
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn affine @affine-test/affine-desktop e2e
|
||||
|
||||
- name: Run desktop tests
|
||||
if: ${{ matrix.spec.test && matrix.spec.os != 'ubuntu-latest' }}
|
||||
run: yarn workspace @affine-test/affine-desktop e2e
|
||||
run: yarn affine @affine-test/affine-desktop e2e
|
||||
|
||||
- name: Make bundle (macOS)
|
||||
if: ${{ matrix.spec.target == 'aarch64-apple-darwin' }}
|
||||
@ -758,7 +757,7 @@ jobs:
|
||||
SKIP_BUNDLE: true
|
||||
SKIP_WEB_BUILD: true
|
||||
HOIST_NODE_MODULES: 1
|
||||
run: yarn workspace @affine/electron package --platform=darwin --arch=arm64
|
||||
run: yarn affine @affine/electron package --platform=darwin --arch=arm64
|
||||
|
||||
- name: Make Bundle (Linux)
|
||||
run: |
|
||||
@ -768,7 +767,7 @@ jobs:
|
||||
flatpak update
|
||||
# some flatpak deps need git protocol.file.allow
|
||||
git config --global protocol.file.allow always
|
||||
yarn workspace @affine/electron make --platform=linux --arch=x64
|
||||
yarn affine @affine/electron make --platform=linux --arch=x64
|
||||
if: ${{ matrix.spec.target == 'x86_64-unknown-linux-gnu' }}
|
||||
env:
|
||||
SKIP_WEB_BUILD: 1
|
||||
@ -777,7 +776,7 @@ jobs:
|
||||
- name: Output check
|
||||
if: ${{ matrix.spec.os == 'macos-14' && matrix.spec.arch == 'arm64' }}
|
||||
run: |
|
||||
yarn workspace @affine/electron exec node --loader ts-node/esm/transpile-only ./scripts/macos-arm64-output-check.ts
|
||||
yarn affine @affine/electron node ./scripts/macos-arm64-output-check.ts
|
||||
|
||||
- name: Upload test results
|
||||
if: ${{ failure() }}
|
||||
|
4
.github/workflows/copilot-test.yml
vendored
4
.github/workflows/copilot-test.yml
vendored
@ -82,7 +82,7 @@ jobs:
|
||||
uses: ./.github/actions/server-test-env
|
||||
|
||||
- name: Run server tests
|
||||
run: yarn workspace @affine/server test:copilot:coverage --forbid-only
|
||||
run: yarn affine @affine/server test:copilot:coverage --forbid-only
|
||||
env:
|
||||
CARGO_TARGET_DIR: '${{ github.workspace }}/target'
|
||||
COPILOT_OPENAI_API_KEY: ${{ secrets.COPILOT_OPENAI_API_KEY }}
|
||||
@ -147,7 +147,7 @@ jobs:
|
||||
- name: Run Copilot E2E Test ${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||
uses: ./.github/actions/copilot-test
|
||||
with:
|
||||
script: yarn workspace @affine-test/affine-cloud-copilot e2e --forbid-only --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||
script: yarn affine @affine-test/affine-cloud-copilot e2e --forbid-only --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||
openai-key: ${{ secrets.COPILOT_OPENAI_API_KEY }}
|
||||
fal-key: ${{ secrets.COPILOT_FAL_API_KEY }}
|
||||
|
||||
|
14
.github/workflows/release-desktop.yml
vendored
14
.github/workflows/release-desktop.yml
vendored
@ -52,7 +52,7 @@ jobs:
|
||||
- name: Setup @sentry/cli
|
||||
uses: ./.github/actions/setup-sentry
|
||||
- name: generate-assets
|
||||
run: yarn workspace @affine/electron generate-assets
|
||||
run: yarn affine @affine/electron generate-assets
|
||||
env:
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: 'affine'
|
||||
@ -122,7 +122,7 @@ jobs:
|
||||
path: packages/frontend/apps/electron/resources/web-static
|
||||
|
||||
- name: Build Desktop Layers
|
||||
run: yarn workspace @affine/electron build
|
||||
run: yarn affine @affine/electron build
|
||||
|
||||
- name: Signing By Apple Developer ID
|
||||
if: ${{ matrix.spec.platform == 'darwin' }}
|
||||
@ -142,7 +142,7 @@ jobs:
|
||||
git config --global protocol.file.allow always
|
||||
|
||||
- name: make
|
||||
run: yarn workspace @affine/electron make --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
run: yarn affine @affine/electron make --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
env:
|
||||
SKIP_WEB_BUILD: 1
|
||||
HOIST_NODE_MODULES: 1
|
||||
@ -236,10 +236,10 @@ jobs:
|
||||
path: packages/frontend/apps/electron/resources/web-static
|
||||
|
||||
- name: Build Desktop Layers
|
||||
run: yarn workspace @affine/electron build
|
||||
run: yarn affine @affine/electron build
|
||||
|
||||
- name: package
|
||||
run: yarn workspace @affine/electron package --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
run: yarn affine @affine/electron package --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
env:
|
||||
SKIP_WEB_BUILD: 1
|
||||
HOIST_NODE_MODULES: 1
|
||||
@ -314,10 +314,10 @@ jobs:
|
||||
run: Expand-Archive -Path signed.zip -DestinationPath packages/frontend/apps/electron/out
|
||||
|
||||
- name: Make squirrel.windows installer
|
||||
run: yarn workspace @affine/electron make-squirrel --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
run: yarn affine @affine/electron make-squirrel --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
|
||||
- name: Make nsis.windows installer
|
||||
run: yarn workspace @affine/electron make-nsis --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
run: yarn affine @affine/electron make-nsis --platform=${{ matrix.spec.platform }} --arch=${{ matrix.spec.arch }}
|
||||
|
||||
- name: Zip artifacts for faster upload
|
||||
run: Compress-Archive -CompressionLevel Fastest -Path packages/frontend/apps/electron/out/${{ env.BUILD_TYPE }}/make/* -DestinationPath archive.zip
|
||||
|
6
.github/workflows/release-mobile.yml
vendored
6
.github/workflows/release-mobile.yml
vendored
@ -68,7 +68,7 @@ jobs:
|
||||
- name: Setup @sentry/cli
|
||||
uses: ./.github/actions/setup-sentry
|
||||
- name: Build Mobile
|
||||
run: yarn workspace @affine/ios build
|
||||
run: yarn affine @affine/ios build
|
||||
env:
|
||||
PUBLIC_PATH: '/'
|
||||
MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_TOKEN }}
|
||||
@ -101,7 +101,7 @@ jobs:
|
||||
- name: Setup @sentry/cli
|
||||
uses: ./.github/actions/setup-sentry
|
||||
- name: Build Mobile
|
||||
run: yarn workspace @affine/android build
|
||||
run: yarn affine @affine/android build
|
||||
env:
|
||||
PUBLIC_PATH: '/'
|
||||
MIXPANEL_TOKEN: ${{ secrets.MIXPANEL_TOKEN }}
|
||||
@ -216,7 +216,7 @@ jobs:
|
||||
- name: Auto increment version code
|
||||
id: bump
|
||||
if: ${{ env.BUILD_TARGET == 'distribution' }}
|
||||
run: yarn workspace @affine/playstore-auto-bump bump
|
||||
run: yarn affine @affine/playstore-auto-bump bump
|
||||
env:
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ steps.auth.outputs.credentials_file_path }}
|
||||
- name: Build
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -80,3 +80,7 @@ apps/web/next-routes.conf
|
||||
|
||||
packages/frontend/templates/edgeless
|
||||
packages/frontend/core/public/static/templates
|
||||
|
||||
# script
|
||||
af
|
||||
af.cmd
|
||||
|
@ -1,30 +1,35 @@
|
||||
yarn.lock
|
||||
target
|
||||
lib
|
||||
test-results
|
||||
.next
|
||||
out
|
||||
dist
|
||||
# we will make this file shared by prettier|eslint|oxlint
|
||||
**/node_modules
|
||||
.yarn
|
||||
.github/helm
|
||||
_next
|
||||
storybook-static
|
||||
web-static
|
||||
public
|
||||
packages/backend/server/src/schema.gql
|
||||
packages/backend/server/src/base/error/errors.gen.ts
|
||||
packages/frontend/i18n/src/i18n-generated.ts
|
||||
packages/frontend/i18n/src/i18n-completenesses.json
|
||||
packages/frontend/graphql/src/graphql/index.ts
|
||||
.github
|
||||
.vscode
|
||||
.yarnrc.yml
|
||||
packages/frontend/templates/*.gen.ts
|
||||
packages/frontend/templates/onboarding
|
||||
|
||||
# auto-generated by NAPI-RS
|
||||
# fixme(@joooye34): need script to check and generate ignore list here
|
||||
# compiled output
|
||||
.coverage
|
||||
.nx/**
|
||||
target
|
||||
test-results
|
||||
**/dist
|
||||
**/lib
|
||||
**/storybook-static
|
||||
**/web-static
|
||||
**/public
|
||||
**/e2e-dist-*
|
||||
**/static
|
||||
|
||||
# generated files
|
||||
**/*.gen.ts
|
||||
**/*.gql
|
||||
**/*.d.ts
|
||||
|
||||
# per files
|
||||
tools/cli/src/webpack/error-handler.js
|
||||
packages/backend/native/index.d.ts
|
||||
packages/frontend/native/index.d.ts
|
||||
packages/frontend/native/index.js
|
||||
compose.yaml
|
||||
|
||||
packages/frontend/graphql/src/graphql/index.ts
|
||||
packages/frontend/graphql/src/schema.ts
|
||||
packages/frontend/apps/android/App/app/build/**
|
||||
blocksuite/tests-legacy/snapshots
|
||||
**/.storybook
|
||||
|
22
.vscode/launch.template.json
vendored
22
.vscode/launch.template.json
vendored
@ -1,25 +1,21 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Dev",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "yarn run dev"
|
||||
},
|
||||
{
|
||||
"name": "Run Dev Locally",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "yarn run dev:local"
|
||||
},
|
||||
{
|
||||
"name": "Launch AFFiNE Cloud",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "yarn",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"runtimeArgs": ["workspace", "@affine/server", "dev"]
|
||||
"runtimeArgs": ["affine", "@affine/server", "dev"]
|
||||
},
|
||||
{
|
||||
"name": "Lanuch AFFiNE Web",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "yarn",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"runtimeArgs": ["affine", "@affine/web", "dev"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -87,13 +87,13 @@ This could take a while if you build it for the first time.
|
||||
Note: use `strip` from system instead of `binutils` if you are running MacOS. [see problem here](https://github.com/toeverything/AFFiNE/discussions/2840)
|
||||
|
||||
```
|
||||
yarn workspace @affine/native build
|
||||
yarn affine @affine/native build
|
||||
```
|
||||
|
||||
### Build Server Dependencies
|
||||
|
||||
```sh
|
||||
yarn workspace @affine/server-native build
|
||||
yarn affine @affine/server-native build
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
@ -46,7 +46,7 @@ Please refer to `Build Native Dependencies` section in [BUILDING.md](./BUILDING.
|
||||
On Mac & Linux
|
||||
|
||||
```shell
|
||||
BUILD_TYPE=canary yarn workspace @affine/electron generate-assets
|
||||
BUILD_TYPE=canary yarn affine @affine/electron generate-assets
|
||||
```
|
||||
|
||||
On Windows (powershell)
|
||||
@ -90,7 +90,7 @@ yarn install
|
||||
Note: you need to comment out `osxSign` and `osxNotarize` in `forge.config.js` to skip signing and notarizing the app.
|
||||
|
||||
```shell
|
||||
BUILD_TYPE=canary SKIP_WEB_BUILD=1 HOIST_NODE_MODULES=1 yarn workspace @affine/electron make
|
||||
BUILD_TYPE=canary SKIP_WEB_BUILD=1 HOIST_NODE_MODULES=1 yarn affine @affine/electron make
|
||||
```
|
||||
|
||||
#### Windows
|
||||
@ -101,9 +101,9 @@ Making the windows installer is a bit different. Right now we provide two instal
|
||||
$env:BUILD_TYPE="canary"
|
||||
$env:SKIP_WEB_BUILD=1
|
||||
$env:HOIST_NODE_MODULES=1
|
||||
yarn workspace @affine/electron package
|
||||
yarn workspace @affine/electron make-squirrel
|
||||
yarn workspace @affine/electron make-nsis
|
||||
yarn affine @affine/electron package
|
||||
yarn affine @affine/electron make-squirrel
|
||||
yarn affine @affine/electron make-nsis
|
||||
```
|
||||
|
||||
Once the build is complete, you can find the paths to the binaries in the terminal output.
|
||||
|
@ -18,7 +18,7 @@ docker compose -f ./.docker/dev/compose.yml up -d
|
||||
|
||||
```sh
|
||||
# build native
|
||||
yarn workspace @affine/server-native build
|
||||
yarn affine @affine/server-native build
|
||||
```
|
||||
|
||||
## Prepare dev environment
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
import eslint from '@eslint/js';
|
||||
import rxjs from '@smarttools/eslint-plugin-rxjs';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
@ -10,33 +12,13 @@ import sonarjs from 'eslint-plugin-sonarjs';
|
||||
import unicorn from 'eslint-plugin-unicorn';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
const ignoreList = readFileSync('.prettierignore', 'utf-8')
|
||||
.split('\n')
|
||||
.filter(line => line.trim() && !line.startsWith('#'));
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules',
|
||||
'**/dist',
|
||||
'**/.next',
|
||||
'**/out',
|
||||
'**/storybook-static',
|
||||
'**/affine-out',
|
||||
'**/_next',
|
||||
'**/lib',
|
||||
'**/.eslintrc.js',
|
||||
'**/e2e-dist-*',
|
||||
'**/static',
|
||||
'**/web-static',
|
||||
'**/public',
|
||||
'**/.coverage',
|
||||
'.nx/**',
|
||||
'.yarn/**',
|
||||
'**/*.d.ts',
|
||||
'.github/**/*',
|
||||
'packages/frontend/component/.storybook/**/*',
|
||||
'packages/frontend/i18n/src/i18n-generated.ts',
|
||||
'packages/frontend/i18n/src/i18n-completenesses.json',
|
||||
'packages/frontend/templates/*.gen.ts',
|
||||
'packages/frontend/apps/android/App/app/build/**',
|
||||
],
|
||||
ignores: ignoreList,
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
@ -218,7 +200,7 @@ export default tseslint.config(
|
||||
{
|
||||
files: [
|
||||
'packages/**/*.{ts,tsx}',
|
||||
'tools/cli/**/*.{ts,tsx}',
|
||||
'tools/**/*.{ts,tsx}',
|
||||
'blocksuite/**/*.{ts,tsx}',
|
||||
],
|
||||
rules: {
|
||||
|
35
oxlint.json
35
oxlint.json
@ -5,13 +5,41 @@
|
||||
"correctness": "error",
|
||||
"perf": "error"
|
||||
},
|
||||
"ignorePatterns": ["tools/cli/src/webpack/error-handler.js"],
|
||||
"ignorePatterns": [
|
||||
"**/node_modules",
|
||||
".yarn",
|
||||
".github",
|
||||
".vscode",
|
||||
".yarnrc.yml",
|
||||
".coverage",
|
||||
".nx/**",
|
||||
"target",
|
||||
"test-results",
|
||||
"**/dist",
|
||||
"**/lib",
|
||||
"**/storybook-static",
|
||||
"**/web-static",
|
||||
"**/public",
|
||||
"**/e2e-dist-*",
|
||||
"**/static",
|
||||
"**/*.gen.ts",
|
||||
"**/*.gql",
|
||||
"**/*.d.ts",
|
||||
"tools/cli/src/webpack/error-handler.js",
|
||||
"packages/backend/native/index.d.ts",
|
||||
"packages/frontend/native/index.d.ts",
|
||||
"packages/frontend/native/index.js",
|
||||
"packages/frontend/graphql/src/graphql/index.ts",
|
||||
"packages/frontend/graphql/src/schema.ts",
|
||||
"packages/frontend/apps/android/App/app/build/**",
|
||||
"blocksuite/tests-legacy/snapshots",
|
||||
"**/.storybook"
|
||||
],
|
||||
"rules": {
|
||||
"import/named": "allow",
|
||||
"no-await-in-loop": "allow",
|
||||
"promise/no-callback-in-promise": "allow",
|
||||
"typescript/ban-types": "allow",
|
||||
|
||||
"array-callback-return": "error",
|
||||
"constructor-super": "error",
|
||||
"eqeqeq": ["error", "smart"],
|
||||
@ -172,7 +200,8 @@
|
||||
"files": [
|
||||
"*.{spec,test,e2e,stories}.{ts,tsx}",
|
||||
"tests/**/*.ts",
|
||||
"packages/backend/server/tests/**/*.ts"
|
||||
"packages/backend/server/tests/**/*.ts",
|
||||
"tools/**.*"
|
||||
],
|
||||
"rules": {
|
||||
"typescript/no-non-null-assertion": "off",
|
||||
|
17
package.json
17
package.json
@ -18,12 +18,10 @@
|
||||
"node": "<21.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "yarn workspace @affine/cli dev",
|
||||
"build": "yarn workspace @affine/cli bundle",
|
||||
"dev:electron": "yarn workspace @affine/electron dev",
|
||||
"build:electron": "yarn workspace @affine/electron build",
|
||||
"build:server-native": "yarn workspace @affine/server-native build",
|
||||
"start:web-static": "yarn workspace @affine/web static-server",
|
||||
"affine": "yarn workspace @affine-tools/cli affine",
|
||||
"af": "yarn workspace @affine-tools/cli affine",
|
||||
"dev": "yarn affine dev",
|
||||
"build": "yarn affine build",
|
||||
"lint:eslint": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" eslint --report-unused-disable-directives-severity=off . --cache",
|
||||
"lint:eslint:fix": "yarn lint:eslint --fix --fix-type problem,suggestion,layout",
|
||||
"lint:prettier": "prettier --ignore-unknown --cache --check .",
|
||||
@ -34,9 +32,8 @@
|
||||
"test": "vitest --run",
|
||||
"test:ui": "vitest --ui",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"typecheck": "tsc -b tsconfig.json",
|
||||
"postinstall": "node ./scripts/check-version.mjs && yarn workspace @affine/i18n i18n-codegen gen && yarn husky install",
|
||||
"prepare": "husky"
|
||||
"typecheck": "tsc -b tsconfig.json --verbose",
|
||||
"postinstall": "yarn affine init && yarn husky"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*": "prettier --write --ignore-unknown --cache",
|
||||
@ -52,7 +49,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@affine/cli": "workspace:*",
|
||||
"@affine-tools/cli": "workspace:*",
|
||||
"@capacitor/cli": "^6.2.0",
|
||||
"@eslint/js": "^9.16.0",
|
||||
"@faker-js/faker": "^9.3.0",
|
||||
|
1
packages/backend/native/index.d.ts
vendored
1
packages/backend/native/index.d.ts
vendored
@ -19,4 +19,3 @@ export declare function mergeUpdatesInApplyWay(updates: Array<Buffer>): Buffer
|
||||
export declare function mintChallengeResponse(resource: string, bits?: number | undefined | null): Promise<string>
|
||||
|
||||
export declare function verifyChallengeResponse(response: string, bits: number, resource: string): Promise<boolean>
|
||||
|
||||
|
@ -11,7 +11,7 @@ yarn
|
||||
### Build Native binding
|
||||
|
||||
```bash
|
||||
yarn workspace @affine/server-native build
|
||||
yarn affine @affine/server-native build
|
||||
```
|
||||
|
||||
### Run server
|
||||
|
@ -9,15 +9,14 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node --loader ts-node/esm/transpile-only.mjs ./src/index.ts",
|
||||
"dev": "nodemon ./src/index.ts",
|
||||
"test": "ava --concurrency 1 --serial",
|
||||
"test:copilot": "ava \"tests/**/copilot-*.spec.ts\"",
|
||||
"test:coverage": "c8 ava --concurrency 1 --serial",
|
||||
"test:copilot:coverage": "c8 ava --timeout=5m \"tests/**/copilot-*.spec.ts\"",
|
||||
"postinstall": "prisma generate",
|
||||
"data-migration": "NODE_ENV=script node --loader ts-node/esm/transpile-only.mjs ./src/data/index.ts",
|
||||
"predeploy": "yarn prisma migrate deploy && node --import ./scripts/register.js ./dist/data/index.js run"
|
||||
"data-migration": "NODE_ENV=script node ./src/data/index.ts",
|
||||
"predeploy": "yarn prisma migrate deploy && node --import ./scripts/register.js ./dist/data/index.js run",
|
||||
"postinstall": "prisma generate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/server": "^4.11.2",
|
||||
@ -119,10 +118,7 @@
|
||||
},
|
||||
"workerThreads": false,
|
||||
"nodeArguments": [
|
||||
"--trace-sigint",
|
||||
"--loader",
|
||||
"ts-node/esm/transpile-only.mjs",
|
||||
"--es-module-specifier-resolution=node"
|
||||
"--trace-sigint"
|
||||
],
|
||||
"watchMode": {
|
||||
"ignoreChanges": [
|
||||
@ -139,7 +135,6 @@
|
||||
"./src/prelude.ts"
|
||||
],
|
||||
"environmentVariables": {
|
||||
"TS_NODE_PROJECT": "./tests/tsconfig.json",
|
||||
"NODE_ENV": "test",
|
||||
"MAILER_HOST": "0.0.0.0",
|
||||
"MAILER_PORT": "1025",
|
||||
@ -152,12 +147,6 @@
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"exec": "node",
|
||||
"script": "./src/index.ts",
|
||||
"nodeArgs": [
|
||||
"--loader",
|
||||
"ts-node/esm.mjs",
|
||||
"--es-module-specifier-resolution=node"
|
||||
],
|
||||
"ignore": [
|
||||
"**/__tests__/**",
|
||||
"**/dist/**",
|
||||
@ -166,8 +155,6 @@
|
||||
"env": {
|
||||
"NODE_ENV": "development",
|
||||
"AFFINE_SERVER_EXTERNAL_URL": "http://localhost:8080",
|
||||
"TS_NODE_TRANSPILE_ONLY": true,
|
||||
"TS_NODE_PROJECT": "./tsconfig.json",
|
||||
"DEBUG": "affine:*",
|
||||
"FORCE_COLOR": true,
|
||||
"DEBUG_COLORS": true
|
||||
|
@ -15,9 +15,6 @@
|
||||
},
|
||||
{
|
||||
"path": "../../../blocksuite/affine/all"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "lib",
|
||||
"noEmit": false
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
@ -62,7 +62,8 @@
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env DISTRIBUTION=admin yarn workspace @affine/cli bundle",
|
||||
"build": "affine bundle",
|
||||
"dev": "affine bundle --dev",
|
||||
"update-shadcn": "shadcn-ui add -p src/components/ui"
|
||||
},
|
||||
"exports": {
|
||||
|
@ -1,7 +1,8 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ['class'],
|
||||
content: ['./src/**/*.{ts,tsx}'],
|
||||
// TODO(@forehalo): we are not running webpack in admin dir
|
||||
content: ['./packages/frontend/admin/src/**/*.{ts,tsx}'],
|
||||
prefix: '',
|
||||
theme: {
|
||||
container: {
|
||||
|
@ -5,6 +5,6 @@ AFFiNE Android app.
|
||||
## Build
|
||||
|
||||
- yarn install
|
||||
- BUILD_TYPE=canary PUBLIC_PATH="/" yarn workspace @affine/android build
|
||||
- yarn workspace @affine/android cap sync
|
||||
- yarn workspace @affine/android cap open android
|
||||
- BUILD_TYPE=canary PUBLIC_PATH="/" yarn affine @affine/android build
|
||||
- yarn affine @affine/android cap sync
|
||||
- yarn affine @affine/android cap open android
|
||||
|
@ -5,9 +5,8 @@
|
||||
"private": true,
|
||||
"browser": "src/index.tsx",
|
||||
"scripts": {
|
||||
"build": "cross-env DISTRIBUTION=android yarn workspace @affine/cli bundle",
|
||||
"dev": "yarn workspace @affine/cli dev",
|
||||
"static-server": "cross-env DISTRIBUTION=android yarn workspace @affine/cli dev --static"
|
||||
"build": "affine bundle",
|
||||
"dev": "affine bundle --dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
|
@ -7,7 +7,7 @@ To run AFFiNE Desktop Client Application locally, run the following commands:
|
||||
```sh
|
||||
# in repo root
|
||||
yarn install
|
||||
yarn workspace @affine/native build
|
||||
yarn affine @affine/native build
|
||||
yarn dev
|
||||
|
||||
# in packages/frontend/apps/electron
|
||||
|
@ -2,6 +2,7 @@
|
||||
"name": "@affine/electron",
|
||||
"private": true,
|
||||
"version": "0.18.0",
|
||||
"main": "./dist/main.js",
|
||||
"author": "toeverything",
|
||||
"repository": {
|
||||
"url": "https://github.com/toeverything/AFFiNE",
|
||||
@ -11,19 +12,20 @@
|
||||
"homepage": "https://github.com/toeverything/AFFiNE",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"dev": "DEV_SERVER_URL=http://localhost:8080 node --loader ts-node/esm/transpile-only ./scripts/dev.ts",
|
||||
"dev:prod": "yarn node --loader ts-node/esm/transpile-only scripts/dev.ts",
|
||||
"build": "NODE_ENV=production node --loader ts-node/esm/transpile-only scripts/build-layers.ts",
|
||||
"build:dev": "NODE_ENV=development node --loader ts-node/esm/transpile-only scripts/build-layers.ts",
|
||||
"generate-assets": "node --loader ts-node/esm/transpile-only scripts/generate-assets.ts",
|
||||
"package": "cross-env NODE_OPTIONS=\"--loader ts-node/esm/transpile-only\" electron-forge package",
|
||||
"make": "cross-env NODE_OPTIONS=\"--loader ts-node/esm/transpile-only\" electron-forge make",
|
||||
"make-squirrel": "node --loader ts-node/esm/transpile-only scripts/make-squirrel.ts",
|
||||
"make-nsis": "node --loader ts-node/esm/transpile-only scripts/make-nsis.ts"
|
||||
"dev": "cross-env DEV_SERVER_URL=http://localhost:8080 node ./scripts/dev.ts",
|
||||
"dev:prod": "node ./scripts/dev.ts",
|
||||
"build": "cross-env NODE_ENV=production node ./scripts/build-layers.ts",
|
||||
"build:dev": "node ./scripts/build-layers.ts",
|
||||
"bundle": "affine bundle",
|
||||
"generate-assets": "node ./scripts/generate-assets.ts",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make",
|
||||
"make-squirrel": "node ./scripts/make-squirrel.ts",
|
||||
"make-nsis": "node ./scripts/make-nsis.ts"
|
||||
},
|
||||
"main": "./dist/main.js",
|
||||
"devDependencies": {
|
||||
"@affine-test/kit": "workspace:*",
|
||||
"@affine-tools/utils": "workspace:*",
|
||||
"@affine/component": "workspace:*",
|
||||
"@affine/core": "workspace:*",
|
||||
"@affine/electron-api": "workspace:*",
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { getBuildConfig } from '@affine/cli/src/webpack/runtime-config';
|
||||
import { getBuildConfig } from '@affine-tools/utils/build-config';
|
||||
import { Package } from '@affine-tools/utils/workspace';
|
||||
import { sentryEsbuildPlugin } from '@sentry/esbuild-plugin';
|
||||
import type { BuildOptions, Plugin } from 'esbuild';
|
||||
|
||||
@ -24,12 +24,10 @@ export const config = (): BuildOptions => {
|
||||
'process.env.NODE_ENV': process.env.NODE_ENV,
|
||||
REPLACE_ME_BUILD_ENV: process.env.BUILD_TYPE ?? 'stable',
|
||||
...Object.entries(
|
||||
getBuildConfig({
|
||||
channel: (process.env.BUILD_TYPE as any) ?? 'canary',
|
||||
distribution: 'desktop',
|
||||
getBuildConfig(new Package('@affine/electron'), {
|
||||
mode:
|
||||
process.env.NODE_ENV === 'production' ? 'production' : 'development',
|
||||
static: false,
|
||||
channel: (process.env.BUILD_TYPE as any) ?? 'canary',
|
||||
})
|
||||
).reduce(
|
||||
(def, [key, val]) => {
|
||||
|
@ -34,6 +34,7 @@ function spawnOrReloadElectron() {
|
||||
const ext = process.platform === 'win32' ? '.cmd' : '';
|
||||
const exe = resolve(rootDir, 'node_modules', '.bin', `electron${ext}`);
|
||||
|
||||
delete process.env['NODE_OPTIONS'];
|
||||
spawnProcess = spawn(exe, ['.'], {
|
||||
cwd: electronDir,
|
||||
env: process.env,
|
||||
|
@ -33,6 +33,9 @@
|
||||
},
|
||||
{
|
||||
"path": "../../../../tests/kit"
|
||||
},
|
||||
{
|
||||
"path": "../../../../tools/utils"
|
||||
}
|
||||
],
|
||||
"ts-node": {
|
||||
|
@ -5,7 +5,7 @@
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "Node",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noEmit": false,
|
||||
"outDir": "./lib/scripts",
|
||||
@ -17,5 +17,10 @@
|
||||
"ts-node": {
|
||||
"esm": true,
|
||||
"experimentalSpecifierResolution": "node"
|
||||
}
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../../tools/utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// TODO(@forehalo): reuse '@affine-tools/utils' once it's ready to switch to esm module
|
||||
import { resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
|
12
packages/frontend/apps/electron/webpack.config.js
Normal file
12
packages/frontend/apps/electron/webpack.config.js
Normal file
@ -0,0 +1,12 @@
|
||||
// TODO(@forehalo): all packages would become 'module'
|
||||
const path = require('node:path');
|
||||
|
||||
module.exports.config = {
|
||||
entry: {
|
||||
app: './renderer/index.tsx',
|
||||
shell: './renderer/shell/index.tsx',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, './renderer/dist'),
|
||||
},
|
||||
};
|
@ -5,9 +5,9 @@ AFFiNE iOS app.
|
||||
## Build
|
||||
|
||||
- `yarn install`
|
||||
- `BUILD_TYPE=canary PUBLIC_PATH="/" yarn workspace @affine/ios build`
|
||||
- `yarn workspace @affine/ios cap sync`
|
||||
- `yarn workspace @affine/ios cap open ios`
|
||||
- `BUILD_TYPE=canary PUBLIC_PATH="/" yarn affine @affine/ios build`
|
||||
- `yarn affine @affine/ios cap sync`
|
||||
- `yarn affine @affine/ios cap open ios`
|
||||
|
||||
## Live Reload
|
||||
|
||||
@ -16,5 +16,5 @@ AFFiNE iOS app.
|
||||
- `yarn install`
|
||||
- `yarn dev`
|
||||
- select `ios` for the "Distribution" option
|
||||
- `yarn workspace @affine/ios sync:dev`
|
||||
- `yarn workspace @affine/ios cap open ios`
|
||||
- `yarn affine @affine/ios sync:dev`
|
||||
- `yarn affine @affine/ios cap open ios`
|
||||
|
@ -5,11 +5,10 @@
|
||||
"private": true,
|
||||
"browser": "src/index.tsx",
|
||||
"scripts": {
|
||||
"build": "cross-env DISTRIBUTION=ios yarn workspace @affine/cli bundle",
|
||||
"dev": "yarn workspace @affine/cli dev",
|
||||
"build": "affine bundle",
|
||||
"dev": "affine bundle --dev",
|
||||
"sync": "yarn cap sync",
|
||||
"sync:dev": "CAP_SERVER_URL=http://localhost:8080 yarn cap sync",
|
||||
"static-server": "cross-env DISTRIBUTION=ios yarn workspace @affine/cli dev --static"
|
||||
"sync:dev": "CAP_SERVER_URL=http://localhost:8080 yarn cap sync"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
|
@ -5,9 +5,8 @@
|
||||
"private": true,
|
||||
"browser": "src/index.tsx",
|
||||
"scripts": {
|
||||
"build": "cross-env DISTRIBUTION=mobile yarn workspace @affine/cli bundle",
|
||||
"dev": "yarn workspace @affine/cli dev",
|
||||
"static-server": "cross-env DISTRIBUTION=mobile yarn workspace @affine/cli dev --static"
|
||||
"build": "affine bundle",
|
||||
"dev": "affine bundle --dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
|
@ -5,9 +5,8 @@
|
||||
"private": true,
|
||||
"browser": "src/index.tsx",
|
||||
"scripts": {
|
||||
"build": "cross-env DISTRIBUTION=web yarn workspace @affine/cli bundle",
|
||||
"dev": "yarn workspace @affine/cli dev",
|
||||
"static-server": "yarn workspace @affine/cli dev --static"
|
||||
"build": "affine bundle",
|
||||
"dev": "affine bundle --dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/component": "workspace:*",
|
||||
|
@ -3,7 +3,7 @@ import { StorybookConfig } from '@storybook/react-vite';
|
||||
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
|
||||
import swc from 'unplugin-swc';
|
||||
import { mergeConfig } from 'vite';
|
||||
import { getBuildConfig } from '@affine/cli/src/webpack/runtime-config';
|
||||
import { getBuildConfig } from '@affine-tools/utils/build-config';
|
||||
|
||||
export default {
|
||||
stories: ['../src/ui/**/*.@(mdx|stories.@(js|jsx|ts|tsx))'],
|
||||
|
@ -20,7 +20,6 @@
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/cli": "workspace:*",
|
||||
"@affine/debug": "workspace:*",
|
||||
"@affine/electron-api": "workspace:*",
|
||||
"@affine/graphql": "workspace:*",
|
||||
|
@ -1,7 +1,12 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"exclude": ["lib"],
|
||||
"include": ["./src/**/*", "./src/**/*.json", "./src/type.d.ts"],
|
||||
"include": [
|
||||
"./src/**/*",
|
||||
"./src/**/*.json",
|
||||
"./src/type.d.ts",
|
||||
"./.storybook"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": false,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Allow: /api/workspaces/*/blobs/*
|
||||
Disallow: /oauth/*
|
||||
Disallow: /workspace/*
|
||||
Disallow: /public-workspace/*
|
||||
|
@ -28,12 +28,6 @@
|
||||
},
|
||||
{
|
||||
"path": "../../../blocksuite/affine/all"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.server.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"verbatimModuleSyntax": false,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "./lib/.webpack",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": [".webpack/*.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../tools/cli"
|
||||
},
|
||||
{
|
||||
"path": "../../common/env"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"outDir": "./lib/server"
|
||||
},
|
||||
"include": ["server.mts"]
|
||||
}
|
@ -30,7 +30,5 @@ generates:
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-operations
|
||||
- add:
|
||||
content: '/* eslint-disable */'
|
||||
- ./export-gql-plugin.cjs:
|
||||
output: ./src/graphql/index.ts
|
||||
|
@ -21,7 +21,7 @@
|
||||
"vitest": "2.1.8"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "gql-gen --errors-only"
|
||||
"build": "gql-gen --errors-only"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine/env": "workspace:*",
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
/* oxlint-disable */
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = T | null;
|
||||
export type Exact<T extends { [key: string]: unknown }> = {
|
||||
|
@ -4,7 +4,7 @@
|
||||
"list": [
|
||||
{
|
||||
"input": "./src/resources/en.json",
|
||||
"output": "./src/i18n-generated",
|
||||
"output": "./src/i18n.gen",
|
||||
"parser": {
|
||||
"type": "i18next",
|
||||
"contextSeparator": "$",
|
||||
|
@ -39,7 +39,7 @@ function calcCompletenesses() {
|
||||
|
||||
writeFileSync(
|
||||
join(pkgRoot, 'src', 'i18n-completenesses.json'),
|
||||
JSON.stringify(completenesses, null, 2)
|
||||
JSON.stringify(completenesses, null, 2) + '\n'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -21,4 +21,4 @@
|
||||
"ur": 2,
|
||||
"zh-Hans": 91,
|
||||
"zh-Hant": 90
|
||||
}
|
||||
}
|
||||
|
6888
packages/frontend/i18n/src/i18n.gen.ts
Normal file
6888
packages/frontend/i18n/src/i18n.gen.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ import type { BackendModule, i18n } from 'i18next';
|
||||
import i18next from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
import type { useAFFiNEI18N } from './i18n-generated';
|
||||
import type { useAFFiNEI18N } from './i18n.gen';
|
||||
import type { Language } from './resources';
|
||||
import { SUPPORTED_LANGUAGES } from './resources';
|
||||
|
||||
|
@ -4,7 +4,8 @@
|
||||
"sideEffect": false,
|
||||
"version": "0.18.0",
|
||||
"scripts": {
|
||||
"postinstall": "node ./build-edgeless.mjs && node ./build-stickers.mjs"
|
||||
"build": "node ./build-edgeless.mjs && node ./build-stickers.mjs",
|
||||
"postinstall": "yarn build"
|
||||
},
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
@ -1,3 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import('@affine/bump-blocksuite');
|
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cargo update -p jwst-codec -p jwst-core -p jwst-storage
|
@ -1,15 +0,0 @@
|
||||
const semver = await import('semver').catch(
|
||||
() => import('../packages/backend/server/node_modules/semver/index.js')
|
||||
);
|
||||
|
||||
import packageJson from '../package.json' with { type: 'json' };
|
||||
|
||||
const { engines } = packageJson;
|
||||
|
||||
const version = engines.node;
|
||||
if (!semver.satisfies(process.version, version)) {
|
||||
console.log(
|
||||
`Required node version ${version} not satisfied with current version ${process.version}.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
const { exec } = await import('node:child_process');
|
||||
const { fileURLToPath } = await import('node:url');
|
||||
const { readdir } = await import('node:fs/promises');
|
||||
const { join } = await import('node:path');
|
||||
|
||||
async function readJsonFromCommit(commit, file) {
|
||||
function readFile(commit, file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`git show ${commit}:${file}`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(stderr);
|
||||
} else {
|
||||
resolve(stdout);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const content = await readFile(commit, file);
|
||||
return JSON.parse(content);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function checkBlocksuiteChanged(oldPkg, newPkg) {
|
||||
const changed = new Set();
|
||||
const keys = ['dependencies', 'devDependencies'];
|
||||
|
||||
keys.forEach(key => {
|
||||
const oldDeps = oldPkg[key] || {};
|
||||
const newDeps = newPkg[key] || {};
|
||||
|
||||
Object.keys(newDeps).forEach(dep => {
|
||||
if (newDeps[dep] !== oldDeps[dep] && dep.startsWith('@blocksuite/')) {
|
||||
changed.add(dep);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
async function findPackageJson(root) {
|
||||
const packages = new Set();
|
||||
|
||||
async function walk(dir) {
|
||||
const files = await readdir(dir, { withFileTypes: true });
|
||||
|
||||
for (const file of files) {
|
||||
if (file.isDirectory() && file.name !== 'node_modules') {
|
||||
await walk(join(dir, file.name));
|
||||
} else if (file.name === 'package.json') {
|
||||
let path = join(dir.replace(root, ''), file.name);
|
||||
if (path.startsWith('/')) {
|
||||
path = path.slice(1);
|
||||
}
|
||||
packages.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await walk(root);
|
||||
|
||||
return packages;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const commitHash = process.argv[2] || process.env.GITHUB_BASE_REF;
|
||||
const currentHead = process.argv[3] || 'HEAD';
|
||||
if (!commitHash) {
|
||||
console.error('Missing base ref commit hash, skipping check.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const changedPackages = new Set();
|
||||
const folders = await findPackageJson(
|
||||
join(fileURLToPath(import.meta.url), '..', '..')
|
||||
);
|
||||
|
||||
for (const packagePath of folders) {
|
||||
const old = await readJsonFromCommit(commitHash, packagePath);
|
||||
const current = await readJsonFromCommit(currentHead, packagePath);
|
||||
console.log('checking:', packagePath);
|
||||
if (
|
||||
old &&
|
||||
current &&
|
||||
typeof old === 'object' &&
|
||||
typeof current === 'object'
|
||||
) {
|
||||
for (const p of checkBlocksuiteChanged(old, current)) {
|
||||
changedPackages.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changedPackages.size > 0) {
|
||||
console.log('Blocksuite packages have been updated.', changedPackages);
|
||||
process.exit(0);
|
||||
} else {
|
||||
console.log('No changes to Blocksuite packages.');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
@ -1,11 +1,10 @@
|
||||
import { getBuildConfig } from '@affine/cli/src/webpack/runtime-config';
|
||||
import { setupGlobal } from '@affine/env/global';
|
||||
import { getBuildConfig } from '@affine-tools/utils/build-config';
|
||||
import { Package } from '@affine-tools/utils/workspace';
|
||||
|
||||
globalThis.BUILD_CONFIG = getBuildConfig({
|
||||
distribution: 'web',
|
||||
globalThis.BUILD_CONFIG = getBuildConfig(new Package('@affine/web'), {
|
||||
mode: 'development',
|
||||
channel: 'canary',
|
||||
static: false,
|
||||
});
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
|
@ -26,9 +26,8 @@ const config: PlaywrightTestConfig = {
|
||||
retries: 3,
|
||||
reporter: process.env.CI ? 'github' : 'list',
|
||||
webServer: [
|
||||
// Intentionally not building the web, reminds you to run it by yourself.
|
||||
{
|
||||
command: 'yarn -T run start:web-static',
|
||||
command: 'yarn run -T affine dev -p @affine/web',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
@ -37,7 +36,7 @@ const config: PlaywrightTestConfig = {
|
||||
},
|
||||
},
|
||||
{
|
||||
command: 'yarn workspace @affine/server start',
|
||||
command: 'yarn run -T affine dev -p @affine/server',
|
||||
port: 3010,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
|
@ -26,9 +26,12 @@ const config: PlaywrightTestConfig = {
|
||||
retries: process.env.COPILOT ? 1 : 3,
|
||||
reporter: process.env.CI ? 'github' : 'list',
|
||||
webServer: [
|
||||
// Intentionally not building the web, reminds you to run it by yourself.
|
||||
{
|
||||
command: 'yarn -T run start:web-static',
|
||||
// TODO(@forehalo):
|
||||
// in ci, all the target will be built,
|
||||
// we could download the builds from archives
|
||||
// and then run the web with simple http serve, it's will be faster
|
||||
command: 'yarn run -T affine dev -p @affine/web',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
@ -37,12 +40,10 @@ const config: PlaywrightTestConfig = {
|
||||
},
|
||||
},
|
||||
{
|
||||
command: 'yarn workspace @affine/server start',
|
||||
command: 'yarn run -T affine dev -p @affine/server',
|
||||
port: 3010,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
env: {
|
||||
DATABASE_URL:
|
||||
process.env.DATABASE_URL ??
|
||||
|
@ -23,7 +23,7 @@ const config: PlaywrightTestConfig = {
|
||||
webServer: [
|
||||
// Intentionally not building the web, reminds you to run it by yourself.
|
||||
{
|
||||
command: 'yarn -T run start:web-static',
|
||||
command: 'yarn run -T affine bundle -p @affine/electron --dev',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
@ -34,7 +34,7 @@ const config: PlaywrightTestConfig = {
|
||||
},
|
||||
},
|
||||
{
|
||||
command: 'yarn workspace @affine/server start',
|
||||
command: 'yarn run -T affine dev -p @affine/server',
|
||||
port: 3010,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
|
@ -41,7 +41,7 @@ if (process.env.DEV_SERVER_URL) {
|
||||
);
|
||||
config.webServer = [
|
||||
{
|
||||
command: 'yarn run start:web-static',
|
||||
command: 'yarn run -T affine bundle -p @affine/electron --dev',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
|
@ -46,7 +46,7 @@ const config: PlaywrightTestConfig = {
|
||||
webServer: [
|
||||
// Intentionally not building the web, reminds you to run it by yourself.
|
||||
{
|
||||
command: 'yarn run start:web-static',
|
||||
command: 'yarn run -T affine dev -p @affine/web',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
|
@ -49,7 +49,7 @@ const config: PlaywrightTestConfig = {
|
||||
webServer: [
|
||||
// Intentionally not building the web, reminds you to run it by yourself.
|
||||
{
|
||||
command: 'yarn workspace @affine/mobile static-server',
|
||||
command: 'yarn run -T affine dev -p @affine/mobile',
|
||||
port: 8080,
|
||||
timeout: 120 * 1000,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
|
@ -53,16 +53,22 @@ const cloudUserSchema = z.object({
|
||||
export const runPrisma = async <T>(
|
||||
cb: (
|
||||
prisma: InstanceType<
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
// oxlint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
typeof import('../../../packages/backend/server/node_modules/@prisma/client').PrismaClient
|
||||
>
|
||||
) => Promise<T>
|
||||
): Promise<T> => {
|
||||
const {
|
||||
PrismaClient,
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
} = require('../../../packages/backend/server/node_modules/@prisma/client');
|
||||
const client = new PrismaClient();
|
||||
// oxlint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
} = await import(
|
||||
'../../../packages/backend/server/node_modules/@prisma/client'
|
||||
);
|
||||
const client = new PrismaClient({
|
||||
datasourceUrl:
|
||||
process.env.DATABASE_URL ||
|
||||
'postgresql://affine:affine@localhost:5432/affine',
|
||||
});
|
||||
await client.$connect();
|
||||
try {
|
||||
return await cb(client);
|
||||
|
@ -1,13 +0,0 @@
|
||||
# Bump BlockSuite
|
||||
|
||||
To update BlockSuite, run following command in project root:
|
||||
|
||||
```sh
|
||||
node scripts/bump-blocksuite.js
|
||||
```
|
||||
|
||||
For network issue, try setting proxy environment variables:
|
||||
|
||||
```sh
|
||||
export http_proxy=http://127.0.0.1:7890
|
||||
```
|
@ -1,176 +0,0 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { Clipboard } from '@napi-rs/clipboard';
|
||||
import {
|
||||
FetchOptions,
|
||||
ProxyOptions,
|
||||
RemoteCallbacks,
|
||||
Repository,
|
||||
Sort,
|
||||
} from '@napi-rs/simple-git';
|
||||
import chalk from 'chalk';
|
||||
import { ProxyAgent, setGlobalDispatcher } from 'undici';
|
||||
|
||||
import corePackage from '../../packages/frontend/core/package.json' with { type: 'json' };
|
||||
|
||||
const clipboard = new Clipboard();
|
||||
|
||||
const oldHash = corePackage.dependencies['@blocksuite/affine'].split('-').pop();
|
||||
|
||||
const info = await fetch('https://registry.npmjs.org/@blocksuite/affine').then(
|
||||
res => res.json()
|
||||
);
|
||||
|
||||
const latestVersion = info['dist-tags'].latest;
|
||||
const latestHash = latestVersion.split('-').pop();
|
||||
const latestGitHead = info.versions[latestHash].gitHead;
|
||||
const oldGitHead = info.versions[oldHash].gitHead;
|
||||
|
||||
if (oldHash === latestHash) {
|
||||
console.info(chalk.greenBright('Already updated'));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.env.http_proxy) {
|
||||
setGlobalDispatcher(new ProxyAgent(process.env.http_proxy));
|
||||
}
|
||||
|
||||
console.info(`Upgrade blocksuite from ${oldHash} -> ${latestHash}`);
|
||||
|
||||
const blockSuiteDeps = execSync(`yarn info -A --name-only --json`, {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
|
||||
const blocksuiteDepsList = blockSuiteDeps
|
||||
.split('\n')
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean)
|
||||
.map(s => s.substring(1, s.length - 1))
|
||||
.filter(
|
||||
s => s.startsWith('@blocksuite') && !s.startsWith('@blocksuite/icons')
|
||||
)
|
||||
.map(s => s.split('@npm').at(0));
|
||||
|
||||
for (const pkg of blocksuiteDepsList) {
|
||||
const command = `yarn up ${pkg}@${latestVersion}`;
|
||||
console.info(chalk.bgCyan(`Executing ${command}`));
|
||||
execSync(command, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
|
||||
console.info(`Upgrade complete`);
|
||||
|
||||
const repo = new Repository(
|
||||
join(fileURLToPath(import.meta.url), '..', '..', '..', '..', 'BlockSuite')
|
||||
);
|
||||
|
||||
const remote = repo.remoteAnonymous(
|
||||
'https://github.com/toeverything/BlockSuite.git'
|
||||
);
|
||||
|
||||
remote.fetch(
|
||||
['master'],
|
||||
new FetchOptions().proxyOptions(new ProxyOptions().auto()).remoteCallback(
|
||||
new RemoteCallbacks().transferProgress(progress => {
|
||||
if (progress.totalDeltas && progress.totalObjects) {
|
||||
console.log(
|
||||
`${(
|
||||
(progress.receivedObjects / progress.totalObjects) * 50 +
|
||||
(progress.indexedDeltas / progress.totalDeltas) * 50
|
||||
).toFixed(2)}%`
|
||||
);
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const commits = {
|
||||
Features: [],
|
||||
Bugfix: [],
|
||||
Refactor: [],
|
||||
Misc: [],
|
||||
};
|
||||
|
||||
if (!latestGitHead) {
|
||||
console.info('latestGitHead is not found');
|
||||
console.info('Skip generating changelog');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
for (const oid of repo
|
||||
.revWalk()
|
||||
.push(latestGitHead)
|
||||
.setSorting(Sort.Time & Sort.Topological)) {
|
||||
if (oid.startsWith(oldGitHead)) {
|
||||
break;
|
||||
}
|
||||
const commit = repo.findCommit(oid);
|
||||
const summary = commit.summary();
|
||||
if (summary.startsWith('feat')) {
|
||||
commits.Features.push(commit);
|
||||
} else if (summary.startsWith('fix')) {
|
||||
commits.Bugfix.push(commit);
|
||||
} else if (summary.startsWith('refactor')) {
|
||||
commits.Refactor.push(commit);
|
||||
} else {
|
||||
commits.Misc.push(commit);
|
||||
}
|
||||
}
|
||||
|
||||
clipboard.setText(await formatCommits(commits));
|
||||
|
||||
console.info(`Changelog copied to clipboard`);
|
||||
|
||||
async function formatCommits(commits) {
|
||||
return `## Features
|
||||
${await Promise.all(commits.Features.map(format)).then(commits =>
|
||||
commits.join('\n')
|
||||
)}
|
||||
|
||||
## Bugfix
|
||||
${await Promise.all(commits.Bugfix.map(format)).then(commits =>
|
||||
commits.join('\n')
|
||||
)}
|
||||
|
||||
## Refactor
|
||||
${await Promise.all(commits.Refactor.map(format)).then(commits =>
|
||||
commits.join('\n')
|
||||
)}
|
||||
|
||||
## Misc
|
||||
${await Promise.all(commits.Misc.map(format)).then(commits =>
|
||||
commits.join('\n')
|
||||
)}
|
||||
`;
|
||||
/**
|
||||
* @param {import('./index').Commit} commit
|
||||
* @returns string
|
||||
*/
|
||||
async function format(commit) {
|
||||
const summary = commit.summary();
|
||||
const match = summary.match(/\(#(\d+)\)/);
|
||||
if (match) {
|
||||
const [_, pull] = match;
|
||||
const pullInfo = await fetch(
|
||||
`https://api.github.com/repos/toeverything/BlockSuite/pulls/${pull}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
},
|
||||
}
|
||||
)
|
||||
.then(res => res.json())
|
||||
.catch(() => ({ user: {} }));
|
||||
const {
|
||||
user: { login },
|
||||
} = pullInfo;
|
||||
return `- https://github.com/toeverything/BlockSuite/pull/${pull} @${login}`;
|
||||
}
|
||||
return `- ${summary}`;
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"name": "@affine/bump-blocksuite",
|
||||
"version": "0.18.0",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"private": true,
|
||||
"description": "Generate changelog from blocksuite version change",
|
||||
"dependencies": {
|
||||
"@napi-rs/clipboard": "^1.1.2",
|
||||
"@napi-rs/simple-git": "^0.1.19",
|
||||
"chalk": "^5.3.0",
|
||||
"undici": "^7.1.0"
|
||||
}
|
||||
}
|
113
tools/cli/README.md
Normal file
113
tools/cli/README.md
Normal file
@ -0,0 +1,113 @@
|
||||
# AFFiNE Monorepo Cli
|
||||
|
||||
## Start
|
||||
|
||||
```bash
|
||||
yarn affine -h
|
||||
```
|
||||
|
||||
### Run build command defined in package.json
|
||||
|
||||
```bash
|
||||
yarn affine i18n build
|
||||
# or
|
||||
yarn build -p i18n
|
||||
```
|
||||
|
||||
### Run dev command defined in package.json
|
||||
|
||||
```bash
|
||||
yarn affine web dev
|
||||
# or
|
||||
yarn dev -p i18n
|
||||
```
|
||||
|
||||
### Clean
|
||||
|
||||
```bash
|
||||
yarn affine clean --dist --rust
|
||||
# clean node_modules
|
||||
yarn affine clean --node-modules
|
||||
```
|
||||
|
||||
### Init
|
||||
|
||||
> Generate files that make the monorepo work properly, the per project codegen will not be included anymore
|
||||
|
||||
```bash
|
||||
yarn affine init
|
||||
```
|
||||
|
||||
## Tricks
|
||||
|
||||
### Define scripts to run a .ts files without `--loader ts-node/esm/transpile-only`
|
||||
|
||||
`affine run` will automatically inject `ts-node`'s transpile service(swc used) for your scripts
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@affine/demo"
|
||||
"scripts": {
|
||||
"dev": "node ./dev.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
affine @affine/demo dev
|
||||
```
|
||||
|
||||
### Short your key presses
|
||||
|
||||
```bash
|
||||
# af is also available for running the scripts
|
||||
yarn af web build
|
||||
```
|
||||
|
||||
#### by custom shell script
|
||||
|
||||
> personally, I use 'af'
|
||||
|
||||
create file `af` in the root of AFFiNE project with the following content
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env sh
|
||||
./tools/scripts/bin/runner.js affine.ts $@
|
||||
```
|
||||
|
||||
or on windows:
|
||||
|
||||
```cmd
|
||||
node "./tools/cli/bin/runner.js" affine.ts %*
|
||||
```
|
||||
|
||||
and give it executable permission
|
||||
|
||||
```bash
|
||||
chmod a+x ./af
|
||||
|
||||
# now you can run scripts with simply
|
||||
./af web build
|
||||
```
|
||||
|
||||
if you want to go further, but for vscode(or other forks) only, add the following to your `.vscode/settings.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"terminal.integrated.env.osx": {
|
||||
"PATH": "${env:PATH}:${cwd}"
|
||||
},
|
||||
"terminal.integrated.env.linux": {
|
||||
"PATH": "${env:PATH}:${cwd}"
|
||||
},
|
||||
"terminal.integrated.env.windows": {
|
||||
"PATH": "${env:PATH};${cwd}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
restart all the integrated terminals and now you get:
|
||||
|
||||
```bash
|
||||
af web build
|
||||
```
|
68
tools/cli/bin/runner.js
Executable file
68
tools/cli/bin/runner.js
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from 'node:child_process';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
|
||||
const scriptsFolder = join(fileURLToPath(import.meta.url), '..', '..');
|
||||
const scriptsSrcFolder = join(scriptsFolder, 'src');
|
||||
const projectRoot = join(scriptsFolder, '..', '..');
|
||||
const loader = join(scriptsFolder, 'register.js');
|
||||
|
||||
const [node, _self, file, ...options] = process.argv;
|
||||
|
||||
if (!file) {
|
||||
console.error(`Please provide a file to run, e.g. 'run src/index.{js/ts}'`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fileLocationCandidates = new Set([
|
||||
process.cwd(),
|
||||
scriptsSrcFolder,
|
||||
projectRoot,
|
||||
]);
|
||||
const lookups = [];
|
||||
|
||||
/**
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
let scriptLocation;
|
||||
for (const location of fileLocationCandidates) {
|
||||
const fileCandidates = [file, `${file}.js`, `${file}.ts`];
|
||||
for (const candidate of fileCandidates) {
|
||||
const candidateLocation = join(location, candidate);
|
||||
if (existsSync(candidateLocation)) {
|
||||
scriptLocation = candidateLocation;
|
||||
break;
|
||||
}
|
||||
lookups.push(candidateLocation);
|
||||
}
|
||||
}
|
||||
|
||||
if (!scriptLocation) {
|
||||
console.error(
|
||||
`File ${file} not found, please make sure the first parameter passed to 'run' script is a valid js or ts file.`
|
||||
);
|
||||
console.error(`Searched locations: `);
|
||||
lookups.forEach(location => {
|
||||
console.error(` - ${location}`);
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const nodeOptions = [];
|
||||
|
||||
if (
|
||||
scriptLocation.endsWith('.ts') ||
|
||||
scriptLocation.startsWith(scriptsFolder)
|
||||
) {
|
||||
nodeOptions.unshift(`--import=${pathToFileURL(loader)}`);
|
||||
} else {
|
||||
nodeOptions.unshift('--experimental-specifier-resolution=node');
|
||||
}
|
||||
|
||||
spawn(node, [...nodeOptions, scriptLocation, ...options], {
|
||||
stdio: 'inherit',
|
||||
}).on('exit', code => {
|
||||
process.exit(code);
|
||||
});
|
14
tools/cli/hooks.js
Normal file
14
tools/cli/hooks.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { create, createEsmHooks, register } from 'ts-node';
|
||||
|
||||
const service = create({
|
||||
experimentalSpecifierResolution: 'node',
|
||||
esm: true,
|
||||
transpileOnly: true,
|
||||
swc: true,
|
||||
});
|
||||
|
||||
register(service);
|
||||
const hooks = createEsmHooks(service);
|
||||
|
||||
export const resolve = hooks.resolve;
|
||||
export const load = hooks.load;
|
@ -1,33 +1,39 @@
|
||||
{
|
||||
"name": "@affine/cli",
|
||||
"name": "@affine-tools/cli",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/templates": "workspace:*",
|
||||
"bin": {
|
||||
"r": "./bin/runner.js"
|
||||
},
|
||||
"exports": {
|
||||
"./loader": "./loader.js"
|
||||
},
|
||||
"scripts": {
|
||||
"affine": "r ./src/affine.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine-tools/utils": "workspace:*",
|
||||
"@aws-sdk/client-s3": "^3.709.0",
|
||||
"@blocksuite/affine": "workspace:*",
|
||||
"@clack/core": "^0.4.0",
|
||||
"@clack/prompts": "^0.9.0",
|
||||
"@magic-works/i18n-codegen": "^0.6.1",
|
||||
"@napi-rs/simple-git": "^0.1.19",
|
||||
"@perfsee/webpack": "^1.13.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
||||
"@sentry/webpack-plugin": "^2.22.7",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/webpack-env": "^1.18.5",
|
||||
"@vanilla-extract/webpack-plugin": "^2.3.15",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"clipanion": "^3.2.1",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"css-loader": "^7.1.2",
|
||||
"cssnano": "^7.0.6",
|
||||
"dotenv": "^16.4.7",
|
||||
"html-webpack-plugin": "^5.6.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mime-types": "^2.1.35",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-loader": "^8.1.1",
|
||||
"prettier": "^3.4.2",
|
||||
"react-refresh": "^0.16.0",
|
||||
"source-map-loader": "^5.0.0",
|
||||
"style-loader": "^4.0.0",
|
||||
@ -35,14 +41,16 @@
|
||||
"tailwindcss": "^3.4.16",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"ts-node": "^10.9.2",
|
||||
"vite": "^6.0.3",
|
||||
"typanion": "^3.14.0",
|
||||
"typescript": "^5.5.4",
|
||||
"webpack": "^5.97.1",
|
||||
"webpack-dev-server": "^5.2.0",
|
||||
"webpack-merge": "^6.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"bundle": "node --loader ts-node/esm/transpile-only.mjs ./src/bin/build.ts",
|
||||
"dev": "node --loader ts-node/esm/transpile-only.mjs ./src/bin/dev.ts"
|
||||
},
|
||||
"version": "0.18.0"
|
||||
"devDependencies": {
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/node": "^20.17.10",
|
||||
"@types/webpack-env": "^1.18.5"
|
||||
}
|
||||
}
|
||||
|
3
tools/cli/register.js
Normal file
3
tools/cli/register.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { register } from 'node:module';
|
||||
|
||||
register('./hooks.js', import.meta.url);
|
32
tools/cli/src/affine.ts
Normal file
32
tools/cli/src/affine.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Workspace } from '@affine-tools/utils/workspace';
|
||||
import { Cli } from 'clipanion';
|
||||
|
||||
import { BuildCommand } from './build';
|
||||
import { BundleCommand } from './bundle';
|
||||
import { CleanCommand } from './clean';
|
||||
import { CodegenCommand } from './codegen';
|
||||
import type { CliContext } from './context';
|
||||
import { DevCommand } from './dev';
|
||||
import { RunCommand } from './run';
|
||||
|
||||
const cli = new Cli<CliContext>({
|
||||
binaryName: 'affine',
|
||||
binaryVersion: '0.0.0',
|
||||
binaryLabel: 'AFFiNE Monorepo Tools',
|
||||
enableColors: true,
|
||||
enableCapture: true,
|
||||
});
|
||||
|
||||
cli.register(RunCommand);
|
||||
cli.register(CodegenCommand);
|
||||
cli.register(CleanCommand);
|
||||
cli.register(BuildCommand);
|
||||
cli.register(DevCommand);
|
||||
cli.register(BundleCommand);
|
||||
|
||||
await cli.runExit(process.argv.slice(2), {
|
||||
workspace: new Workspace(),
|
||||
stdin: process.stdin,
|
||||
stdout: process.stdout,
|
||||
stderr: process.stderr,
|
||||
});
|
@ -1,66 +0,0 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
import webpack from 'webpack';
|
||||
|
||||
import { getCwdFromDistribution } from '../config/cwd.cjs';
|
||||
import type { BuildFlags } from '../config/index.js';
|
||||
import { createWebpackConfig } from '../webpack/webpack.config.js';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const buildType = process.env.BUILD_TYPE_OVERRIDE || process.env.BUILD_TYPE;
|
||||
|
||||
if (process.env.BUILD_TYPE_OVERRIDE) {
|
||||
process.env.BUILD_TYPE = process.env.BUILD_TYPE_OVERRIDE;
|
||||
}
|
||||
|
||||
const getChannel = () => {
|
||||
switch (buildType) {
|
||||
case 'canary':
|
||||
case 'beta':
|
||||
case 'stable':
|
||||
case 'internal':
|
||||
return buildType;
|
||||
case '':
|
||||
throw new Error('BUILD_TYPE is not set');
|
||||
default: {
|
||||
throw new Error(
|
||||
`BUILD_TYPE must be one of canary, beta, stable, internal, received [${buildType}]`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let entry: BuildFlags['entry'];
|
||||
|
||||
const { DISTRIBUTION = 'web' } = process.env;
|
||||
|
||||
const cwd = getCwdFromDistribution(DISTRIBUTION);
|
||||
|
||||
if (DISTRIBUTION === 'desktop') {
|
||||
entry = { app: './index.tsx', shell: './shell/index.tsx' };
|
||||
}
|
||||
|
||||
const flags = {
|
||||
distribution: DISTRIBUTION as BuildFlags['distribution'],
|
||||
mode: 'production',
|
||||
channel: getChannel(),
|
||||
coverage: process.env.COVERAGE === 'true',
|
||||
entry,
|
||||
static: false,
|
||||
} satisfies BuildFlags;
|
||||
|
||||
spawn('yarn', ['workspace', '@affine/i18n', 'build'], {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
webpack(createWebpackConfig(cwd!, flags), (err, stats) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
if (stats?.hasErrors()) {
|
||||
console.error(stats.toString('errors-only'));
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
@ -1,146 +0,0 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import * as p from '@clack/prompts';
|
||||
import { config } from 'dotenv';
|
||||
import webpack from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
|
||||
import { getCwdFromDistribution, projectRoot } from '../config/cwd.cjs';
|
||||
import type { BuildFlags } from '../config/index.js';
|
||||
import { createWebpackConfig } from '../webpack/webpack.config.js';
|
||||
|
||||
const flags: BuildFlags = {
|
||||
distribution:
|
||||
(process.env.DISTRIBUTION as BuildFlags['distribution']) ?? 'web',
|
||||
mode: 'development',
|
||||
static: false,
|
||||
channel: 'canary',
|
||||
coverage: process.env.COVERAGE === 'true',
|
||||
};
|
||||
|
||||
const files = ['.env', '.env.local'];
|
||||
|
||||
for (const file of files) {
|
||||
if (existsSync(join(projectRoot, file))) {
|
||||
config({
|
||||
path: join(projectRoot, file),
|
||||
});
|
||||
console.log(`${file} loaded`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const buildFlags = process.argv.includes('--static')
|
||||
? { ...flags, static: true }
|
||||
: ((await p.group(
|
||||
{
|
||||
distribution: () =>
|
||||
p.select({
|
||||
message: 'Distribution',
|
||||
options: [
|
||||
{
|
||||
value: 'web',
|
||||
},
|
||||
{
|
||||
value: 'desktop',
|
||||
},
|
||||
{
|
||||
value: 'admin',
|
||||
},
|
||||
{
|
||||
value: 'mobile',
|
||||
},
|
||||
{
|
||||
value: 'ios',
|
||||
},
|
||||
],
|
||||
initialValue: 'web',
|
||||
}),
|
||||
mode: () =>
|
||||
p.select({
|
||||
message: 'Mode',
|
||||
options: [
|
||||
{
|
||||
value: 'development',
|
||||
},
|
||||
{
|
||||
value: 'production',
|
||||
},
|
||||
],
|
||||
initialValue: 'development',
|
||||
}),
|
||||
channel: () =>
|
||||
p.select({
|
||||
message: 'Channel',
|
||||
options: [
|
||||
{
|
||||
value: 'canary',
|
||||
},
|
||||
{
|
||||
value: 'beta',
|
||||
},
|
||||
{
|
||||
value: 'stable',
|
||||
},
|
||||
],
|
||||
initialValue: 'canary',
|
||||
}),
|
||||
coverage: () =>
|
||||
p.confirm({
|
||||
message: 'Enable coverage',
|
||||
initialValue: process.env.COVERAGE === 'true',
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('Operation cancelled.');
|
||||
process.exit(0);
|
||||
},
|
||||
}
|
||||
)) as BuildFlags);
|
||||
|
||||
flags.distribution = buildFlags.distribution;
|
||||
flags.mode = buildFlags.mode;
|
||||
flags.channel = buildFlags.channel;
|
||||
flags.coverage = buildFlags.coverage;
|
||||
flags.static = buildFlags.static;
|
||||
flags.entry = undefined;
|
||||
|
||||
const cwd = getCwdFromDistribution(flags.distribution);
|
||||
|
||||
process.env.DISTRIBUTION = flags.distribution;
|
||||
|
||||
if (flags.distribution === 'desktop') {
|
||||
flags.entry = {
|
||||
app: join(cwd, 'index.tsx'),
|
||||
shell: join(cwd, 'shell/index.tsx'),
|
||||
};
|
||||
}
|
||||
|
||||
console.info(flags);
|
||||
|
||||
if (!flags.static) {
|
||||
spawn('yarn', ['workspace', '@affine/i18n', 'dev'], {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
// @ts-expect-error no types
|
||||
await import('@affine/templates/build-edgeless');
|
||||
const config = createWebpackConfig(cwd, flags);
|
||||
if (flags.static) {
|
||||
config.watch = false;
|
||||
}
|
||||
const compiler = webpack(config);
|
||||
// Start webpack
|
||||
const devServer = new WebpackDevServer(config.devServer, compiler);
|
||||
|
||||
await devServer.start();
|
||||
} catch (error) {
|
||||
console.error('Error during build:', error);
|
||||
process.exit(1);
|
||||
}
|
15
tools/cli/src/build.ts
Normal file
15
tools/cli/src/build.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { PackageCommand } from './command';
|
||||
|
||||
export class BuildCommand extends PackageCommand {
|
||||
static override paths = [['build'], ['b']];
|
||||
|
||||
async execute() {
|
||||
const args = ['affine build', this.package];
|
||||
|
||||
if (this.deps) {
|
||||
args.push('--deps');
|
||||
}
|
||||
|
||||
await this.cli.run(args);
|
||||
}
|
||||
}
|
93
tools/cli/src/bundle.ts
Normal file
93
tools/cli/src/bundle.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import webpack, { type Compiler, type Configuration } from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import { Option, PackageCommand } from './command';
|
||||
import { createWebpackConfig } from './webpack';
|
||||
|
||||
function getChannel() {
|
||||
const channel = process.env.BUILD_TYPE ?? 'canary';
|
||||
switch (channel) {
|
||||
case 'canary':
|
||||
case 'beta':
|
||||
case 'stable':
|
||||
case 'internal':
|
||||
return channel;
|
||||
default: {
|
||||
throw new Error(
|
||||
`BUILD_TYPE must be one of canary, beta, stable, internal, received [${channel}]`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BundleCommand extends PackageCommand {
|
||||
static override paths = [['bundle'], ['webpack'], ['pack'], ['bun']];
|
||||
|
||||
// bundle is not able to run with deps
|
||||
override deps = false;
|
||||
|
||||
dev = Option.Boolean('--dev,-d', false, {
|
||||
description: 'Run in Development mode',
|
||||
});
|
||||
|
||||
async execute() {
|
||||
this.logger.info(`Packing package ${this.package}...`);
|
||||
|
||||
const config = await this.getConfig();
|
||||
|
||||
const compiler = webpack(config);
|
||||
|
||||
if (this.dev) {
|
||||
await this.start(compiler, config.devServer);
|
||||
} else {
|
||||
await this.build(compiler);
|
||||
}
|
||||
}
|
||||
|
||||
async getConfig() {
|
||||
let config = createWebpackConfig(this.workspace.getPackage(this.package), {
|
||||
mode: this.dev ? 'development' : 'production',
|
||||
channel: getChannel(),
|
||||
});
|
||||
|
||||
let configOverride: Configuration | undefined;
|
||||
const overrideConfigPath = this.workspace
|
||||
.getPackage(this.package)
|
||||
.join('webpack.config.js');
|
||||
|
||||
if (overrideConfigPath.isFile()) {
|
||||
const override = await import(overrideConfigPath.value);
|
||||
configOverride = override.config ?? override.default;
|
||||
}
|
||||
|
||||
if (configOverride) {
|
||||
config = merge(config, configOverride);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
async start(compiler: Compiler, config: Configuration['devServer']) {
|
||||
const devServer = new WebpackDevServer(config, compiler);
|
||||
|
||||
await devServer.start();
|
||||
}
|
||||
|
||||
async build(compiler: Compiler) {
|
||||
compiler.run((error, stats) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
if (stats) {
|
||||
if (stats.hasErrors()) {
|
||||
console.error(stats.toString('errors-only'));
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log(stats.toString('minimal'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
71
tools/cli/src/clean.ts
Normal file
71
tools/cli/src/clean.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { rmSync } from 'node:fs';
|
||||
|
||||
import { exec } from '@affine-tools/utils/process';
|
||||
|
||||
import { Command, Option } from './command';
|
||||
|
||||
export class CleanCommand extends Command {
|
||||
static override paths = [['clean']];
|
||||
|
||||
cleanDist = Option.Boolean('--dist', false);
|
||||
cleanRustTarget = Option.Boolean('--rust', false);
|
||||
cleanNodeModules = Option.Boolean('--node-modules', false);
|
||||
all = Option.Boolean('--all,-a', false);
|
||||
|
||||
async execute() {
|
||||
this.logger.info('Cleaning Workspace...');
|
||||
if (this.all || this.cleanNodeModules) {
|
||||
this.doCleanNodeModules();
|
||||
}
|
||||
|
||||
if (this.all || this.cleanDist) {
|
||||
this.doCleanDist();
|
||||
}
|
||||
|
||||
if (this.all || this.cleanRustTarget) {
|
||||
this.doCleanRust();
|
||||
}
|
||||
}
|
||||
|
||||
doCleanNodeModules() {
|
||||
this.logger.info('Cleaning node_modules...');
|
||||
|
||||
const rootNodeModules = this.workspace.join('node_modules');
|
||||
if (rootNodeModules.isDirectory()) {
|
||||
this.logger.info(`Cleaning ${rootNodeModules}`);
|
||||
rmSync(rootNodeModules.value, { recursive: true });
|
||||
}
|
||||
|
||||
this.workspace.forEach(pkg => {
|
||||
const nodeModules = pkg.nodeModulesPath;
|
||||
if (nodeModules.isDirectory()) {
|
||||
this.logger.info(`Cleaning ${nodeModules}`);
|
||||
rmSync(nodeModules.value, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.info('node_modules cleaned');
|
||||
}
|
||||
|
||||
doCleanDist() {
|
||||
this.logger.info('Cleaning dist...');
|
||||
|
||||
this.workspace.forEach(pkg => {
|
||||
if (pkg.distPath.isDirectory()) {
|
||||
this.logger.info(`Cleaning ${pkg.distPath}`);
|
||||
rmSync(pkg.distPath.value, { recursive: true });
|
||||
}
|
||||
|
||||
if (pkg.libPath.isDirectory()) {
|
||||
this.logger.info(`Cleaning ${pkg.libPath}`);
|
||||
rmSync(pkg.libPath.value, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
this.logger.info('dist cleaned');
|
||||
}
|
||||
|
||||
doCleanRust() {
|
||||
exec('', 'cargo clean');
|
||||
}
|
||||
}
|
67
tools/cli/src/codegen.ts
Executable file
67
tools/cli/src/codegen.ts
Executable file
@ -0,0 +1,67 @@
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
|
||||
import type { Path } from '@affine-tools/utils/path';
|
||||
import { type BuiltInParserName, format } from 'prettier';
|
||||
|
||||
import { Command } from './command';
|
||||
|
||||
export class CodegenCommand extends Command {
|
||||
static override paths = [['init'], ['i'], ['codegen']];
|
||||
|
||||
async execute() {
|
||||
this.logger.info('Generating Workspace configs');
|
||||
await this.generateWorkspaceFiles();
|
||||
this.logger.info('Workspace configs generated');
|
||||
}
|
||||
|
||||
async generateWorkspaceFiles() {
|
||||
const filesToGenerate: [Path, () => string, BuiltInParserName?][] = [
|
||||
[
|
||||
this.workspace.join('tsconfig.project.json'),
|
||||
this.workspace.genProjectTsConfig.bind(this.workspace),
|
||||
'json',
|
||||
],
|
||||
[
|
||||
this.workspace
|
||||
.getPackage('@affine-tools/utils')
|
||||
.join('src/workspace.gen.ts'),
|
||||
this.workspace.genWorkspaceInfo.bind(this.workspace),
|
||||
'typescript',
|
||||
],
|
||||
[this.workspace.join('oxlint.json'), this.genOxlintConfig, 'json'],
|
||||
];
|
||||
|
||||
for (const [path, content, formatter] of filesToGenerate) {
|
||||
this.logger.info(`Output: ${path}`);
|
||||
let file = content();
|
||||
if (formatter) {
|
||||
file = await this.format(file, formatter);
|
||||
}
|
||||
writeFileSync(path.value, file);
|
||||
}
|
||||
}
|
||||
|
||||
format(content: string, parser: BuiltInParserName) {
|
||||
const config = JSON.parse(
|
||||
readFileSync(this.workspace.join('.prettierrc').value, 'utf-8')
|
||||
);
|
||||
return format(content, { parser, ...config });
|
||||
}
|
||||
|
||||
genOxlintConfig = () => {
|
||||
const json = JSON.parse(
|
||||
readFileSync(this.workspace.join('oxlint.json').value, 'utf-8')
|
||||
);
|
||||
|
||||
const ignoreList = readFileSync(
|
||||
this.workspace.join('.prettierignore').value,
|
||||
'utf-8'
|
||||
)
|
||||
.split('\n')
|
||||
.filter(line => line.trim() && !line.startsWith('#'));
|
||||
|
||||
json['ignorePatterns'] = ignoreList;
|
||||
|
||||
return JSON.stringify(json, null, 2);
|
||||
};
|
||||
}
|
71
tools/cli/src/command.ts
Normal file
71
tools/cli/src/command.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { AliasToPackage } from '@affine-tools/utils/distribution';
|
||||
import { Logger } from '@affine-tools/utils/logger';
|
||||
import { type PackageName, Workspace } from '@affine-tools/utils/workspace';
|
||||
import { Command as BaseCommand, Option } from 'clipanion';
|
||||
import * as t from 'typanion';
|
||||
|
||||
import type { CliContext } from './context';
|
||||
|
||||
export abstract class Command extends BaseCommand<CliContext> {
|
||||
get logger() {
|
||||
// @ts-expect-error hack: Get the command name
|
||||
return new Logger(this.constructor.paths[0][0]);
|
||||
}
|
||||
|
||||
get workspace() {
|
||||
return this.context.workspace;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class PackageCommand extends Command {
|
||||
protected availablePackageNameArgs = (
|
||||
Workspace.PackageNames as string[]
|
||||
).concat(Array.from(AliasToPackage.keys()));
|
||||
protected packageNameValidator = t.isOneOf(
|
||||
this.availablePackageNameArgs.map(k => t.isLiteral(k))
|
||||
);
|
||||
|
||||
protected packageNameOrAlias = Option.String('--package,-p', {
|
||||
required: true,
|
||||
validator: this.packageNameValidator,
|
||||
description: 'The package name or alias to be run with',
|
||||
});
|
||||
|
||||
get package(): PackageName {
|
||||
return (
|
||||
AliasToPackage.get(this.packageNameOrAlias as any) ??
|
||||
(this.packageNameOrAlias as PackageName)
|
||||
);
|
||||
}
|
||||
|
||||
deps = Option.Boolean('--deps', false, {
|
||||
description:
|
||||
'Execute the same command in workspace dependencies, if defined.',
|
||||
});
|
||||
}
|
||||
|
||||
export abstract class PackagesCommand extends Command {
|
||||
protected availablePackageNameArgs = (
|
||||
Workspace.PackageNames as string[]
|
||||
).concat(Array.from(AliasToPackage.keys()));
|
||||
protected packageNameValidator = t.isOneOf(
|
||||
this.availablePackageNameArgs.map(k => t.isLiteral(k))
|
||||
);
|
||||
|
||||
protected packageNamesOrAliases = Option.Array('--package,-p', {
|
||||
required: true,
|
||||
validator: t.isArray(this.packageNameValidator),
|
||||
});
|
||||
get packages() {
|
||||
return this.packageNamesOrAliases.map(
|
||||
name => AliasToPackage.get(name as any) ?? name
|
||||
);
|
||||
}
|
||||
|
||||
deps = Option.Boolean('--deps', false, {
|
||||
description:
|
||||
'Execute the same command in workspace dependencies, if defined.',
|
||||
});
|
||||
}
|
||||
|
||||
export { Option };
|
@ -1,38 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
const { join } = require('node:path');
|
||||
|
||||
const projectRoot = join(__dirname, '../../../..');
|
||||
|
||||
module.exports.projectRoot = projectRoot;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string | undefined} distribution
|
||||
* @returns string
|
||||
*/
|
||||
module.exports.getCwdFromDistribution = function getCwdFromDistribution(
|
||||
distribution
|
||||
) {
|
||||
switch (distribution) {
|
||||
case 'web':
|
||||
case undefined:
|
||||
case null:
|
||||
return join(projectRoot, 'packages/frontend/apps/web');
|
||||
case 'desktop':
|
||||
return join(projectRoot, 'packages/frontend/apps/electron/renderer');
|
||||
case 'admin':
|
||||
return join(projectRoot, 'packages/frontend/admin');
|
||||
case 'mobile':
|
||||
return join(projectRoot, 'packages/frontend/apps/mobile');
|
||||
case 'ios':
|
||||
return join(projectRoot, 'packages/frontend/apps/ios');
|
||||
case 'android':
|
||||
return join(projectRoot, 'packages/frontend/apps/android');
|
||||
default: {
|
||||
throw new Error(
|
||||
'DISTRIBUTION must be one of web, desktop, admin, mobile'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
export type BuildFlags = {
|
||||
distribution: 'web' | 'desktop' | 'admin' | 'mobile' | 'ios' | 'android';
|
||||
mode: 'development' | 'production';
|
||||
channel: 'stable' | 'beta' | 'canary' | 'internal';
|
||||
static: boolean;
|
||||
coverage?: boolean;
|
||||
localBlockSuite?: string;
|
||||
entry?: string | { [key: string]: string };
|
||||
};
|
6
tools/cli/src/context.ts
Normal file
6
tools/cli/src/context.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import type { Workspace } from '@affine-tools/utils/workspace';
|
||||
import type { BaseContext } from 'clipanion';
|
||||
|
||||
export interface CliContext extends BaseContext {
|
||||
workspace: Workspace;
|
||||
}
|
15
tools/cli/src/dev.ts
Normal file
15
tools/cli/src/dev.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { PackageCommand } from './command';
|
||||
|
||||
export class DevCommand extends PackageCommand {
|
||||
static override paths = [['dev'], ['d']];
|
||||
|
||||
async execute() {
|
||||
const args = [this.package, 'dev'];
|
||||
|
||||
if (this.deps) {
|
||||
args.push('--deps');
|
||||
}
|
||||
|
||||
await this.cli.run(args);
|
||||
}
|
||||
}
|
135
tools/cli/src/run.ts
Normal file
135
tools/cli/src/run.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import { Path } from '@affine-tools/utils/path';
|
||||
import { execAsync } from '@affine-tools/utils/process';
|
||||
import type { PackageName } from '@affine-tools/utils/workspace';
|
||||
|
||||
import { Option, PackageCommand } from './command';
|
||||
|
||||
interface RunScriptOptions {
|
||||
includeDependencies?: boolean;
|
||||
waitDependencies?: boolean;
|
||||
}
|
||||
|
||||
const currentDir = Path.dir(import.meta.url);
|
||||
|
||||
const ignoreLoaderScripts = [
|
||||
'vitest',
|
||||
'vite',
|
||||
'ts-node',
|
||||
'prisma',
|
||||
'cap',
|
||||
'tsc',
|
||||
/electron(?!-)/,
|
||||
];
|
||||
|
||||
export class RunCommand extends PackageCommand {
|
||||
static override paths = [[], ['run'], ['r']];
|
||||
|
||||
static override usage = PackageCommand.Usage({
|
||||
description: 'AFFiNE Monorepo scripts',
|
||||
details: `
|
||||
\`affine web <script>\` Run any script defined in package's package.json
|
||||
|
||||
\`affine codegen\` Generate the required files if there are any package added or removed
|
||||
|
||||
\`affine clean\` Clean the output files of ts, cargo, webpack, etc.
|
||||
|
||||
\`affine bundle\` Bundle the packages
|
||||
|
||||
\`affine build\` A proxy for <-p package>'s \`build\` script
|
||||
|
||||
\`affine dev\` A proxy for <-p package>'s \`dev\` script
|
||||
`,
|
||||
examples: [
|
||||
[`See detail of each command`, '$0 -h'],
|
||||
[
|
||||
`Run custom 'xxx' script defined in @affine/web's package.json`,
|
||||
'$0 web xxx',
|
||||
],
|
||||
[`Run 'codegen' for workspace`, '$0 codegen'],
|
||||
[`Clean tsbuild and dist under each package`, '$0 clean --ts --dist'],
|
||||
[`Clean node_modules under each package`, '$0 clean --node-modules'],
|
||||
[`Clean everything`, '$0 clean --all'],
|
||||
[`Run 'build' script for @affine/web`, '$0 build -p web'],
|
||||
[
|
||||
`Run 'build' script for @affine/web with all deps prebuild before`,
|
||||
'$0 build -p web --deps',
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
// we use positional arguments instead of options
|
||||
protected override packageNameOrAlias: string = Option.String({
|
||||
required: true,
|
||||
validator: this.packageNameValidator,
|
||||
});
|
||||
|
||||
args = Option.Proxy({ name: 'args', required: 1 });
|
||||
|
||||
async execute() {
|
||||
await this.run(this.package, this.args, {
|
||||
includeDependencies: this.deps,
|
||||
waitDependencies: true,
|
||||
});
|
||||
}
|
||||
|
||||
async run(name: PackageName, args: string[], opts: RunScriptOptions = {}) {
|
||||
opts = { includeDependencies: false, ...opts };
|
||||
|
||||
const pkg = this.workspace.getPackage(name);
|
||||
const script = args[0];
|
||||
const pkgScript = pkg.scripts[script];
|
||||
|
||||
let isPackageJsonScript = false;
|
||||
let isAFFiNEScript = false;
|
||||
|
||||
if (pkgScript) {
|
||||
isPackageJsonScript = true;
|
||||
isAFFiNEScript = pkgScript.startsWith('affine ');
|
||||
} else {
|
||||
isAFFiNEScript = script.startsWith('affine ');
|
||||
}
|
||||
|
||||
if (isPackageJsonScript && opts.includeDependencies) {
|
||||
this.logger.info(
|
||||
`Running [${script}] script in dependencies of ${pkg.name}...`
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
pkg.deps.map(dep => {
|
||||
this.logger.info(`Running [${script}] script in ${dep.name}...`);
|
||||
return this.run(dep.name, args, opts);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (isPackageJsonScript) {
|
||||
this.logger.info(`Running [${script}] script in ${pkg.name}...`);
|
||||
}
|
||||
|
||||
if (isAFFiNEScript) {
|
||||
await this.cli.run([
|
||||
...pkgScript.split(' ').slice(1),
|
||||
...args.slice(1),
|
||||
'-p',
|
||||
pkg.name,
|
||||
]);
|
||||
} else {
|
||||
const script = pkgScript ?? args[0];
|
||||
// very simple test for auto ts/mjs scripts
|
||||
const isLoaderRequired = !ignoreLoaderScripts.some(ignore =>
|
||||
new RegExp(ignore).test(script)
|
||||
);
|
||||
|
||||
await execAsync(name, ['yarn', ...args], {
|
||||
cwd: pkg.path.value,
|
||||
...(isLoaderRequired
|
||||
? {
|
||||
env: {
|
||||
NODE_OPTIONS: `--import=${currentDir.join('../register.js').toFileUrl()}`,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import { build } from 'vite';
|
||||
|
||||
import { projectRoot } from '../config/cwd.cjs';
|
||||
|
||||
const infraFilePath = resolve(
|
||||
projectRoot,
|
||||
'packages',
|
||||
'infra',
|
||||
'vite.config.ts'
|
||||
);
|
||||
export const buildInfra = async () => {
|
||||
await build({
|
||||
configFile: infraFilePath,
|
||||
});
|
||||
};
|
||||
|
||||
export const watchInfra = async () => {
|
||||
spawn('vite', ['build', '--watch'], {
|
||||
cwd: resolve(projectRoot, 'packages/common/infra'),
|
||||
shell: true,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
};
|
197
tools/cli/src/webpack/html-plugin.ts
Normal file
197
tools/cli/src/webpack/html-plugin.ts
Normal file
@ -0,0 +1,197 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
import type { BUILD_CONFIG_TYPE } from '@affine/env/global';
|
||||
import { Path, ProjectRoot } from '@affine-tools/utils/path';
|
||||
import { Repository } from '@napi-rs/simple-git';
|
||||
import HTMLPlugin from 'html-webpack-plugin';
|
||||
import once from 'lodash-es/once';
|
||||
import type { Compiler, WebpackPluginInstance } from 'webpack';
|
||||
import webpack from 'webpack';
|
||||
|
||||
import type { BuildFlags } from './types.js';
|
||||
|
||||
export const getPublicPath = (
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
) => {
|
||||
const { BUILD_TYPE } = process.env;
|
||||
if (typeof process.env.PUBLIC_PATH === 'string') {
|
||||
return process.env.PUBLIC_PATH;
|
||||
}
|
||||
|
||||
if (
|
||||
flags.mode === 'development' ||
|
||||
BUILD_CONFIG.distribution === 'desktop' ||
|
||||
BUILD_CONFIG.distribution === 'ios' ||
|
||||
BUILD_CONFIG.distribution === 'android'
|
||||
) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
switch (BUILD_TYPE) {
|
||||
case 'stable':
|
||||
return 'https://prod.affineassets.com/';
|
||||
case 'beta':
|
||||
return 'https://beta.affineassets.com/';
|
||||
default:
|
||||
return 'https://dev.affineassets.com/';
|
||||
}
|
||||
};
|
||||
|
||||
const DESCRIPTION = `There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together.`;
|
||||
|
||||
const gitShortHash = once(() => {
|
||||
const { GITHUB_SHA } = process.env;
|
||||
if (GITHUB_SHA) {
|
||||
return GITHUB_SHA.substring(0, 9);
|
||||
}
|
||||
const repo = new Repository(ProjectRoot.path);
|
||||
const shortSha = repo.head().target()?.substring(0, 9);
|
||||
if (shortSha) {
|
||||
return shortSha;
|
||||
}
|
||||
const sha = execSync(`git rev-parse --short HEAD`, {
|
||||
encoding: 'utf-8',
|
||||
}).trim();
|
||||
return sha;
|
||||
});
|
||||
|
||||
const currentDir = Path.dir(import.meta.url);
|
||||
|
||||
function getHTMLPluginOptions(
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
) {
|
||||
const publicPath = getPublicPath(flags, BUILD_CONFIG);
|
||||
const cdnOrigin = publicPath.startsWith('/')
|
||||
? undefined
|
||||
: new URL(publicPath).origin;
|
||||
|
||||
const templateParams = {
|
||||
GIT_SHORT_SHA: gitShortHash(),
|
||||
DESCRIPTION,
|
||||
PRECONNECT: cdnOrigin
|
||||
? `<link rel="preconnect" href="${cdnOrigin}" />`
|
||||
: '',
|
||||
VIEWPORT_FIT: BUILD_CONFIG.isMobileEdition ? 'cover' : 'auto',
|
||||
};
|
||||
|
||||
return {
|
||||
template: currentDir.join('template.html').toString(),
|
||||
inject: 'body',
|
||||
filename: 'index.html',
|
||||
minify: false,
|
||||
templateParameters: templateParams,
|
||||
chunks: ['app'],
|
||||
} satisfies HTMLPlugin.Options;
|
||||
}
|
||||
|
||||
export function createShellHTMLPlugin(
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
) {
|
||||
const htmlPluginOptions = getHTMLPluginOptions(flags, BUILD_CONFIG);
|
||||
|
||||
return new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
chunks: ['shell'],
|
||||
filename: `shell.html`,
|
||||
});
|
||||
}
|
||||
|
||||
export function createHTMLPlugins(
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
): WebpackPluginInstance[] {
|
||||
const publicPath = getPublicPath(flags, BUILD_CONFIG);
|
||||
const globalErrorHandler = [
|
||||
'js/global-error-handler.js',
|
||||
readFileSync(currentDir.join('./error-handler.js').toString(), 'utf-8'),
|
||||
];
|
||||
|
||||
const htmlPluginOptions = getHTMLPluginOptions(flags, BUILD_CONFIG);
|
||||
|
||||
return [
|
||||
{
|
||||
apply(compiler: Compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
'assets-manifest-plugin',
|
||||
compilation => {
|
||||
HTMLPlugin.getHooks(compilation).beforeAssetTagGeneration.tap(
|
||||
'assets-manifest-plugin',
|
||||
arg => {
|
||||
if (
|
||||
!BUILD_CONFIG.isElectron &&
|
||||
!compilation.getAsset(globalErrorHandler[0])
|
||||
) {
|
||||
compilation.emitAsset(
|
||||
globalErrorHandler[0],
|
||||
new webpack.sources.RawSource(globalErrorHandler[1])
|
||||
);
|
||||
arg.assets.js.unshift(
|
||||
arg.assets.publicPath + globalErrorHandler[0]
|
||||
);
|
||||
}
|
||||
|
||||
if (!compilation.getAsset('assets-manifest.json')) {
|
||||
compilation.emitAsset(
|
||||
globalErrorHandler[0],
|
||||
new webpack.sources.RawSource(globalErrorHandler[1])
|
||||
);
|
||||
compilation.emitAsset(
|
||||
`assets-manifest.json`,
|
||||
new webpack.sources.RawSource(
|
||||
JSON.stringify(
|
||||
{
|
||||
...arg.assets,
|
||||
js: arg.assets.js.map(file =>
|
||||
file.substring(arg.assets.publicPath.length)
|
||||
),
|
||||
css: arg.assets.css.map(file =>
|
||||
file.substring(arg.assets.publicPath.length)
|
||||
),
|
||||
gitHash:
|
||||
htmlPluginOptions.templateParameters.GIT_SHORT_SHA,
|
||||
description:
|
||||
htmlPluginOptions.templateParameters.DESCRIPTION,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
),
|
||||
{
|
||||
immutable: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
publicPath,
|
||||
meta: {
|
||||
'env:publicPath': publicPath,
|
||||
},
|
||||
}),
|
||||
// selfhost html
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
meta: {
|
||||
'env:isSelfHosted': 'true',
|
||||
'env:publicPath': '/',
|
||||
},
|
||||
filename: 'selfhost.html',
|
||||
templateParameters: {
|
||||
...htmlPluginOptions.templateParameters,
|
||||
PRECONNECT: '',
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
@ -1,32 +1,33 @@
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
import type { BUILD_CONFIG_TYPE } from '@affine/env/global';
|
||||
import { getBuildConfig } from '@affine-tools/utils/build-config';
|
||||
import { ProjectRoot } from '@affine-tools/utils/path';
|
||||
import type { Package } from '@affine-tools/utils/workspace';
|
||||
import { PerfseePlugin } from '@perfsee/webpack';
|
||||
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import { sentryWebpackPlugin } from '@sentry/webpack-plugin';
|
||||
import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin';
|
||||
import CopyPlugin from 'copy-webpack-plugin';
|
||||
import { compact } from 'lodash-es';
|
||||
import compact from 'lodash-es/compact';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import type { Configuration as DevServerConfiguration } from 'webpack-dev-server';
|
||||
|
||||
import { projectRoot } from '../config/cwd.cjs';
|
||||
import type { BuildFlags } from '../config/index.js';
|
||||
import { productionCacheGroups } from './cache-group.js';
|
||||
import { createHTMLPlugins, createShellHTMLPlugin } from './html-plugin.js';
|
||||
import { WebpackS3Plugin } from './s3-plugin.js';
|
||||
import type { BuildFlags } from './types';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
const IN_CI = !!process.env.CI;
|
||||
|
||||
export const rootPath = join(fileURLToPath(import.meta.url), '..', '..');
|
||||
export const workspaceRoot = join(rootPath, '..', '..', '..');
|
||||
|
||||
const OptimizeOptionOptions: (
|
||||
buildFlags: BuildFlags
|
||||
) => webpack.Configuration['optimization'] = buildFlags => ({
|
||||
minimize: buildFlags.mode === 'production',
|
||||
flags: BuildFlags
|
||||
) => webpack.Configuration['optimization'] = flags => ({
|
||||
minimize: flags.mode === 'production',
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: TerserPlugin.swcMinify,
|
||||
@ -60,71 +61,48 @@ const OptimizeOptionOptions: (
|
||||
},
|
||||
});
|
||||
|
||||
export const getPublicPath = (buildFlags: BuildFlags) => {
|
||||
const { BUILD_TYPE } = process.env;
|
||||
if (typeof process.env.PUBLIC_PATH === 'string') {
|
||||
return process.env.PUBLIC_PATH;
|
||||
}
|
||||
export function createWebpackConfig(
|
||||
pkg: Package,
|
||||
flags: BuildFlags
|
||||
): webpack.Configuration {
|
||||
const buildConfig = getBuildConfig(pkg, flags);
|
||||
|
||||
if (
|
||||
buildFlags.mode === 'development' ||
|
||||
process.env.COVERAGE ||
|
||||
buildFlags.distribution === 'desktop' ||
|
||||
buildFlags.distribution === 'ios' ||
|
||||
buildFlags.distribution === 'android'
|
||||
) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
switch (BUILD_TYPE) {
|
||||
case 'stable':
|
||||
return 'https://prod.affineassets.com/';
|
||||
case 'beta':
|
||||
return 'https://beta.affineassets.com/';
|
||||
default:
|
||||
return 'https://dev.affineassets.com/';
|
||||
}
|
||||
};
|
||||
|
||||
export const createConfiguration: (
|
||||
cwd: string,
|
||||
buildFlags: BuildFlags,
|
||||
buildConfig: BUILD_CONFIG_TYPE
|
||||
) => webpack.Configuration = (cwd, buildFlags, buildConfig) => {
|
||||
const config = {
|
||||
name: 'affine',
|
||||
// to set a correct base path for the source map
|
||||
context: cwd,
|
||||
context: pkg.path.value,
|
||||
experiments: {
|
||||
topLevelAwait: true,
|
||||
outputModule: false,
|
||||
syncWebAssembly: true,
|
||||
},
|
||||
entry: {
|
||||
app: pkg.entry ?? './src/index.tsx',
|
||||
},
|
||||
output: {
|
||||
environment: {
|
||||
module: true,
|
||||
dynamicImport: true,
|
||||
},
|
||||
filename:
|
||||
buildFlags.mode === 'production'
|
||||
flags.mode === 'production'
|
||||
? 'js/[name].[contenthash:8].js'
|
||||
: 'js/[name].js',
|
||||
// In some cases webpack will emit files starts with "_" which is reserved in web extension.
|
||||
chunkFilename: pathData =>
|
||||
pathData.chunk?.name?.endsWith?.('worker')
|
||||
? 'js/[name].[contenthash:8].js'
|
||||
: buildFlags.mode === 'production'
|
||||
: flags.mode === 'production'
|
||||
? 'js/chunk.[name].[contenthash:8].js'
|
||||
: 'js/chunk.[name].js',
|
||||
assetModuleFilename:
|
||||
buildFlags.mode === 'production'
|
||||
flags.mode === 'production'
|
||||
? 'assets/[name].[contenthash:8][ext][query]'
|
||||
: '[name].[contenthash:8][ext]',
|
||||
devtoolModuleFilenameTemplate: 'webpack://[namespace]/[resource-path]',
|
||||
hotUpdateChunkFilename: 'hot/[id].[fullhash].js',
|
||||
hotUpdateMainFilename: 'hot/[runtime].[fullhash].json',
|
||||
path: join(cwd, 'dist'),
|
||||
clean: buildFlags.mode === 'production',
|
||||
path: pkg.distPath.value,
|
||||
clean: flags.mode === 'production',
|
||||
globalObject: 'globalThis',
|
||||
// NOTE(@forehalo): always keep it '/'
|
||||
publicPath: '/',
|
||||
@ -132,10 +110,10 @@ export const createConfiguration: (
|
||||
},
|
||||
target: ['web', 'es2022'],
|
||||
|
||||
mode: buildFlags.mode,
|
||||
mode: flags.mode,
|
||||
|
||||
devtool:
|
||||
buildFlags.mode === 'production'
|
||||
flags.mode === 'production'
|
||||
? 'source-map'
|
||||
: 'eval-cheap-module-source-map',
|
||||
|
||||
@ -147,14 +125,13 @@ export const createConfiguration: (
|
||||
},
|
||||
extensions: ['.js', '.ts', '.tsx'],
|
||||
alias: {
|
||||
yjs: join(workspaceRoot, 'node_modules', 'yjs'),
|
||||
lit: join(workspaceRoot, 'node_modules', 'lit'),
|
||||
'@preact/signals-core': join(
|
||||
workspaceRoot,
|
||||
yjs: ProjectRoot.join('node_modules', 'yjs').value,
|
||||
lit: ProjectRoot.join('node_modules', 'lit').value,
|
||||
'@preact/signals-core': ProjectRoot.join(
|
||||
'node_modules',
|
||||
'@preact',
|
||||
'signals-core'
|
||||
),
|
||||
).value,
|
||||
},
|
||||
},
|
||||
|
||||
@ -230,7 +207,7 @@ export const createConfiguration: (
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'automatic',
|
||||
refresh: buildFlags.mode === 'development' && {
|
||||
refresh: flags.mode === 'development' && {
|
||||
refreshReg: '$RefreshReg$',
|
||||
refreshSig: '$RefreshSig$',
|
||||
emitFullSignatures: true,
|
||||
@ -263,7 +240,7 @@ export const createConfiguration: (
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
buildFlags.mode === 'development'
|
||||
flags.mode === 'development'
|
||||
? 'style-loader'
|
||||
: MiniCssExtractPlugin.loader,
|
||||
{
|
||||
@ -280,7 +257,25 @@ export const createConfiguration: (
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
postcssOptions: {
|
||||
config: join(rootPath, 'webpack', 'postcss.config.cjs'),
|
||||
plugins: [
|
||||
cssnano({
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
convertValues: false,
|
||||
},
|
||||
],
|
||||
}),
|
||||
].concat(
|
||||
pkg.join('tailwind.config.js').exists()
|
||||
? [
|
||||
require('tailwindcss')(
|
||||
require(pkg.join('tailwind.config.js').path)
|
||||
),
|
||||
'autoprefixer',
|
||||
]
|
||||
: []
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -292,7 +287,7 @@ export const createConfiguration: (
|
||||
},
|
||||
plugins: compact([
|
||||
IN_CI ? null : new webpack.ProgressPlugin({ percentBy: 'entries' }),
|
||||
buildFlags.mode === 'development'
|
||||
flags.mode === 'development'
|
||||
? new ReactRefreshWebpackPlugin({
|
||||
overlay: false,
|
||||
esModule: true,
|
||||
@ -305,7 +300,7 @@ export const createConfiguration: (
|
||||
}),
|
||||
new VanillaExtractPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(buildFlags.mode),
|
||||
'process.env.NODE_ENV': JSON.stringify(flags.mode),
|
||||
'process.env.CAPTCHA_SITE_KEY': JSON.stringify(
|
||||
process.env.CAPTCHA_SITE_KEY
|
||||
),
|
||||
@ -323,24 +318,19 @@ export const createConfiguration: (
|
||||
{} as Record<string, string>
|
||||
),
|
||||
}),
|
||||
buildFlags.distribution === 'admin'
|
||||
buildConfig.isAdmin
|
||||
? null
|
||||
: new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
// copy the shared public assets into dist
|
||||
from: join(
|
||||
workspaceRoot,
|
||||
'packages',
|
||||
'frontend',
|
||||
'core',
|
||||
'public'
|
||||
),
|
||||
to: join(cwd, 'dist'),
|
||||
from: pkg.workspace.getPackage('@affine/core').join('public')
|
||||
.value,
|
||||
to: pkg.distPath.value,
|
||||
},
|
||||
],
|
||||
}),
|
||||
buildFlags.mode === 'production' &&
|
||||
flags.mode === 'production' &&
|
||||
(buildConfig.isWeb || buildConfig.isMobileWeb || buildConfig.isAdmin) &&
|
||||
process.env.R2_SECRET_ACCESS_KEY
|
||||
? new WebpackS3Plugin()
|
||||
@ -349,14 +339,12 @@ export const createConfiguration: (
|
||||
stats: {
|
||||
errorDetails: true,
|
||||
},
|
||||
|
||||
optimization: OptimizeOptionOptions(buildFlags),
|
||||
|
||||
optimization: OptimizeOptionOptions(flags),
|
||||
devServer: {
|
||||
host: '0.0.0.0',
|
||||
allowedHosts: 'all',
|
||||
hot: buildFlags.static ? false : 'only',
|
||||
liveReload: !buildFlags.static,
|
||||
hot: true,
|
||||
liveReload: true,
|
||||
client: {
|
||||
overlay: process.env.DISABLE_DEV_OVERLAY === 'true' ? false : undefined,
|
||||
},
|
||||
@ -374,20 +362,10 @@ export const createConfiguration: (
|
||||
},
|
||||
static: [
|
||||
{
|
||||
directory: join(
|
||||
projectRoot,
|
||||
'packages',
|
||||
'frontend',
|
||||
'core',
|
||||
'public'
|
||||
),
|
||||
directory: pkg.workspace.getPackage('@affine/core').join('public')
|
||||
.value,
|
||||
publicPath: '/',
|
||||
watch: !buildFlags.static,
|
||||
},
|
||||
{
|
||||
directory: join(cwd, 'public'),
|
||||
publicPath: '/',
|
||||
watch: !buildFlags.static,
|
||||
watch: true,
|
||||
},
|
||||
],
|
||||
proxy: [
|
||||
@ -404,7 +382,7 @@ export const createConfiguration: (
|
||||
} as DevServerConfiguration,
|
||||
} satisfies webpack.Configuration;
|
||||
|
||||
if (buildFlags.mode === 'production' && process.env.PERFSEE_TOKEN) {
|
||||
if (flags.mode === 'production' && process.env.PERFSEE_TOKEN) {
|
||||
config.plugins.push(
|
||||
new PerfseePlugin({
|
||||
project: 'affine-toeverything',
|
||||
@ -412,7 +390,7 @@ export const createConfiguration: (
|
||||
);
|
||||
}
|
||||
|
||||
if (buildFlags.mode === 'development') {
|
||||
if (flags.mode === 'development') {
|
||||
config.optimization = {
|
||||
...config.optimization,
|
||||
minimize: false,
|
||||
@ -456,5 +434,11 @@ export const createConfiguration: (
|
||||
);
|
||||
}
|
||||
|
||||
config.plugins = config.plugins.concat(createHTMLPlugins(flags, buildConfig));
|
||||
|
||||
if (buildConfig.isElectron) {
|
||||
config.plugins.push(createShellHTMLPlugin(flags, buildConfig));
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
const { join } = require('node:path');
|
||||
|
||||
const cssnano = require('cssnano');
|
||||
const tailwindcss = require('tailwindcss');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
const { getCwdFromDistribution } = require('../config/cwd.cjs');
|
||||
|
||||
const projectCwd = getCwdFromDistribution(process.env.DISTRIBUTION);
|
||||
|
||||
const twConfig = (function () {
|
||||
try {
|
||||
const config = require(`${projectCwd}/tailwind.config.js`);
|
||||
const { content } = config;
|
||||
if (Array.isArray(content)) {
|
||||
config.content = content.map(c =>
|
||||
c.startsWith(projectCwd) ? c : join(projectCwd, c)
|
||||
);
|
||||
}
|
||||
return config;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
module.exports = function (context) {
|
||||
const plugins = [
|
||||
cssnano({
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
convertValues: false,
|
||||
},
|
||||
],
|
||||
}),
|
||||
];
|
||||
|
||||
if (twConfig) {
|
||||
plugins.push(tailwindcss(twConfig), autoprefixer());
|
||||
}
|
||||
|
||||
return {
|
||||
from: context.from,
|
||||
plugins,
|
||||
to: context.to,
|
||||
};
|
||||
};
|
@ -15,9 +15,7 @@ export class WebpackS3Plugin implements WebpackPluginInstance {
|
||||
region: 'auto',
|
||||
endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
||||
credentials: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
accessKeyId: process.env.R2_ACCESS_KEY_ID!,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
|
||||
},
|
||||
});
|
||||
|
4
tools/cli/src/webpack/types.ts
Normal file
4
tools/cli/src/webpack/types.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface BuildFlags {
|
||||
mode: 'development' | 'production';
|
||||
channel: 'stable' | 'beta' | 'canary' | 'internal';
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
|
||||
import type { BuildFlags } from '@affine/cli/config';
|
||||
import { Repository } from '@napi-rs/simple-git';
|
||||
import HTMLPlugin from 'html-webpack-plugin';
|
||||
import { once } from 'lodash-es';
|
||||
import type { Compiler } from 'webpack';
|
||||
import webpack from 'webpack';
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import {
|
||||
createConfiguration,
|
||||
getPublicPath,
|
||||
rootPath,
|
||||
workspaceRoot,
|
||||
} from './config.js';
|
||||
import { getBuildConfig } from './runtime-config.js';
|
||||
|
||||
const DESCRIPTION = `There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together.`;
|
||||
|
||||
const gitShortHash = once(() => {
|
||||
const { GITHUB_SHA } = process.env;
|
||||
if (GITHUB_SHA) {
|
||||
return GITHUB_SHA.substring(0, 9);
|
||||
}
|
||||
const repo = new Repository(workspaceRoot);
|
||||
const shortSha = repo.head().target()?.substring(0, 9);
|
||||
if (shortSha) {
|
||||
return shortSha;
|
||||
}
|
||||
const sha = execSync(`git rev-parse --short HEAD`, {
|
||||
encoding: 'utf-8',
|
||||
}).trim();
|
||||
return sha;
|
||||
});
|
||||
|
||||
export function createWebpackConfig(cwd: string, flags: BuildFlags) {
|
||||
console.log('build flags', flags);
|
||||
const runtimeConfig = getBuildConfig(flags);
|
||||
console.log('BUILD_CONFIG', runtimeConfig);
|
||||
const config = createConfiguration(cwd, flags, runtimeConfig);
|
||||
const entry =
|
||||
typeof flags.entry === 'string' || !flags.entry
|
||||
? {
|
||||
app: flags.entry ?? resolve(cwd, 'src/index.tsx'),
|
||||
}
|
||||
: flags.entry;
|
||||
|
||||
const publicPath = getPublicPath(flags);
|
||||
const cdnOrigin = publicPath.startsWith('/')
|
||||
? undefined
|
||||
: new URL(publicPath).origin;
|
||||
|
||||
const globalErrorHandler = [
|
||||
'js/global-error-handler.js',
|
||||
readFileSync(
|
||||
join(workspaceRoot, 'tools/cli/src/webpack/error-handler.js'),
|
||||
'utf-8'
|
||||
),
|
||||
];
|
||||
|
||||
const templateParams = {
|
||||
GIT_SHORT_SHA: gitShortHash(),
|
||||
DESCRIPTION,
|
||||
PRECONNECT: cdnOrigin
|
||||
? `<link rel="preconnect" href="${cdnOrigin}" />`
|
||||
: '',
|
||||
VIEWPORT_FIT:
|
||||
flags.distribution === 'mobile' ||
|
||||
flags.distribution === 'ios' ||
|
||||
flags.distribution === 'android'
|
||||
? 'cover'
|
||||
: 'auto',
|
||||
};
|
||||
|
||||
const createHTMLPlugins = (entryName: string) => {
|
||||
const htmlPluginOptions = {
|
||||
template: join(rootPath, 'webpack', 'template.html'),
|
||||
inject: 'body',
|
||||
filename: 'index.html',
|
||||
minify: false,
|
||||
templateParameters: templateParams,
|
||||
chunks: [entryName],
|
||||
} satisfies HTMLPlugin.Options;
|
||||
|
||||
if (entryName === 'app') {
|
||||
return [
|
||||
{
|
||||
apply(compiler: Compiler) {
|
||||
compiler.hooks.compilation.tap(
|
||||
'assets-manifest-plugin',
|
||||
compilation => {
|
||||
HTMLPlugin.getHooks(compilation).beforeAssetTagGeneration.tap(
|
||||
'assets-manifest-plugin',
|
||||
arg => {
|
||||
if (
|
||||
flags.distribution !== 'desktop' &&
|
||||
!compilation.getAsset(globalErrorHandler[0])
|
||||
) {
|
||||
compilation.emitAsset(
|
||||
globalErrorHandler[0],
|
||||
new webpack.sources.RawSource(globalErrorHandler[1])
|
||||
);
|
||||
arg.assets.js.unshift(
|
||||
arg.assets.publicPath + globalErrorHandler[0]
|
||||
);
|
||||
}
|
||||
|
||||
if (!compilation.getAsset('assets-manifest.json')) {
|
||||
compilation.emitAsset(
|
||||
globalErrorHandler[0],
|
||||
new webpack.sources.RawSource(globalErrorHandler[1])
|
||||
);
|
||||
compilation.emitAsset(
|
||||
`assets-manifest.json`,
|
||||
new webpack.sources.RawSource(
|
||||
JSON.stringify(
|
||||
{
|
||||
...arg.assets,
|
||||
js: arg.assets.js.map(file =>
|
||||
file.substring(arg.assets.publicPath.length)
|
||||
),
|
||||
css: arg.assets.css.map(file =>
|
||||
file.substring(arg.assets.publicPath.length)
|
||||
),
|
||||
gitHash: templateParams.GIT_SHORT_SHA,
|
||||
description: templateParams.DESCRIPTION,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
),
|
||||
{
|
||||
immutable: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
publicPath,
|
||||
meta: {
|
||||
'env:publicPath': publicPath,
|
||||
},
|
||||
}),
|
||||
// selfhost html
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
meta: {
|
||||
'env:isSelfHosted': 'true',
|
||||
'env:publicPath': '/',
|
||||
},
|
||||
filename: 'selfhost.html',
|
||||
templateParameters: {
|
||||
...htmlPluginOptions.templateParameters,
|
||||
PRECONNECT: '',
|
||||
},
|
||||
}),
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
filename: `${entryName}.html`,
|
||||
}),
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
return merge(config, {
|
||||
entry,
|
||||
plugins: Object.keys(entry).map(createHTMLPlugins).flat(),
|
||||
});
|
||||
}
|
@ -2,11 +2,12 @@
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"allowJs": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"outDir": "lib"
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["src", "package.json"],
|
||||
"references": [{ "path": "../../packages/common/env" }]
|
||||
"include": ["./src"],
|
||||
"references": [
|
||||
{ "path": "../../packages/common/env" },
|
||||
{ "path": "../utils" }
|
||||
]
|
||||
}
|
||||
|
@ -14,12 +14,9 @@
|
||||
"ios",
|
||||
"android",
|
||||
"docs",
|
||||
"storybook",
|
||||
"component",
|
||||
"workspace",
|
||||
"env",
|
||||
"graphql",
|
||||
"cli",
|
||||
"hooks",
|
||||
"i18n",
|
||||
"native",
|
||||
@ -27,7 +24,8 @@
|
||||
"debug",
|
||||
"nbstore",
|
||||
"infra",
|
||||
"editor"
|
||||
"editor",
|
||||
"tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { Package } from '@affine-tools/utils/workspace';
|
||||
import {
|
||||
androidpublisher_v3,
|
||||
auth as google_auth,
|
||||
@ -55,13 +54,10 @@ export async function fetchVersionCode(applicationId: string): Promise<number> {
|
||||
}
|
||||
|
||||
const versionCodeRegexPattern = /(versionCode(?:\s|=)*)(.*)/;
|
||||
const gradlePath = join(
|
||||
fileURLToPath(import.meta.url),
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'packages/frontend/apps/android/App/app/build.gradle'
|
||||
);
|
||||
|
||||
const gradlePath = new Package('@affine/android').join(
|
||||
'App/app/build.gradle'
|
||||
).value;
|
||||
|
||||
let gradleVersionCode = 0;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
"bump": "node --import @oxc-node/core/register index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine-tools/utils": "workspace:*",
|
||||
"@googleapis/androidpublisher": "^22.0.0",
|
||||
"@oxc-node/core": "^0.0.16"
|
||||
},
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user