Skip to content

enhance(backend): bundle backend using Rolldown#17068

Merged
syuilo merged 36 commits intomisskey-dev:developfrom
kakkokari-gtyih:bundle-backend-alt
Apr 16, 2026
Merged

enhance(backend): bundle backend using Rolldown#17068
syuilo merged 36 commits intomisskey-dev:developfrom
kakkokari-gtyih:bundle-backend-alt

Conversation

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor

@kakkokari-gtyih kakkokari-gtyih commented Jan 6, 2026

What

  • rolldownでバックエンドをバンドル(e2e用のみswcから移行していない)
  • production build時はsourcemapを生成しないように
  • バックエンドの開発サーバーのファイルwatch・サーバー起動/終了をrolldownで行うようにし、nodemonを削除
    • rolldown内部でネイティブにwatchするためより効率的
    • ビルドステップに統合されるpluginとしてサーバーの起動制御を実装しているため、より安定してサーバーの起動終了制御が可能に
  • 起動速度の改善 enhance: 起動からlistenまでかかる時間を減らす MisskeyIO/misskey#1410
  • パスが絡む処理において、絶対パスの解決をconfig.tsで一回だけ行い、引き回すように
  • パスが絡む処理でconfigから来た絶対パスを使用するように

Why

Fix #16852

Additional info (optional)

Checklist

  • Read the contribution guide
  • Test working in a local environment
  • (If needed) Add story of storybook
  • (If needed) Update CHANGELOG.md
  • (If possible) Add tests

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 6, 2026

このPRによるapi.jsonの差分
差分はありません。
Get diff files from Workflow Page

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

kakkokari-gtyih commented Jan 6, 2026

コード54.4MBになった(が、起動には成功してない)

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

通常ならその直後に InstanceLoader: EndpointsModule dependencies initialized が出るからEndpointsModuleに原因がある可能性がある

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

どっちかというと EndpointsModule というよりは EndpointsModule に依存している ServerModule かも

@samunohito
Copy link
Copy Markdown
Member

関係あるかわからないけど…

クラス名は維持しておかないとDI周りが死ぬので、バンドルの過程でクラス名などが変わっているのであれば維持するようにしてみるといいかも…?

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

どっちかというと EndpointsModule というよりは EndpointsModule に依存している ServerModule かも

いやさらに ServerModule に依存している CoreModule かも
CoreModule が含んでいる何らかの Service のどれかに問題がありそう(SearchServiceのログは出てるから最低でもそこまでは読み込めていることは判る)

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

いかのどれかに問題があることは絞り込めた

		AbuseUserReportEntityService,
		AnnouncementEntityService,
		AbuseReportNotificationRecipientEntityService,
		AntennaEntityService,
		AppEntityService,
		AuthSessionEntityService,
		BlockingEntityService,
		ChannelEntityService,
		ChatEntityService,
		ClipEntityService,
		DriveFileEntityService,
		DriveFolderEntityService,
		EmojiEntityService,
		FollowingEntityService,
		FollowRequestEntityService,
		GalleryLikeEntityService,
		GalleryPostEntityService,
		HashtagEntityService,
		InstanceEntityService,
		InviteCodeEntityService,
		ModerationLogEntityService,
		MutingEntityService,
		RenoteMutingEntityService,
		NoteEntityService,
		NoteFavoriteEntityService,
		NoteReactionEntityService,
		NoteDraftEntityService,
		NotificationEntityService,
		PageEntityService,
		PageLikeEntityService,
		SigninEntityService,
		UserEntityService,
		UserListEntityService,
		FlashEntityService,
		FlashLikeEntityService,
		RoleEntityService,
		ReversiGameEntityService,
		MetaEntityService,

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

クラス名は維持しておかないとDI周りが死ぬ

keepNamesしてるのでそれはなさそう

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

NoteEntityService に問題があることが判った

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

NoteEntityServiceは循環参照があり、読み込み順的にはModuleRefを使用する初めてのサービスであるので、ModuleRefを使用していることが原因ということで間違いないと思われる

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 6, 2026

Codecov Report

❌ Patch coverage is 72.72727% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.42%. Comparing base (a18c909) to head (24bd03a).
⚠️ Report is 33 commits behind head on develop.

Files with missing lines Patch % Lines
packages/backend/src/boot/common.ts 36.36% 7 Missing ⚠️
...ages/backend/src/server/web/ClientServerService.ts 80.00% 7 Missing ⚠️
...ages/backend/src/server/web/HtmlTemplateService.ts 50.00% 6 Missing ⚠️
packages/backend/src/boot/entry.ts 0.00% 3 Missing ⚠️
packages/backend/src/server/FileServerService.ts 87.50% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #17068      +/-   ##
===========================================
- Coverage    63.65%   62.42%   -1.23%     
===========================================
  Files         1161     1162       +1     
  Lines       116313   116557     +244     
  Branches      8407     9080     +673     
===========================================
- Hits         74042    72764    -1278     
- Misses       40063    41601    +1538     
+ Partials      2208     2192      -16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

NoteEntityServiceは循環参照があり、読み込み順的にはModuleRefを使用する初めてのサービスであるので、ModuleRefを使用していることが原因ということで間違いないと思われる

いや嘘かも

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

InstanceEntityServiceだけ読み込まれてないかも

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

謎ということが判った

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

とはいえ循環参照周りが原因な気はする

@anatawa12
Copy link
Copy Markdown
Member

バンドルでesmoduleそのままだと発生しない循環参照問題が発生するなら minify だけにしたい気がしてます。今後devなら問題ないのにbuildすると謎フリーズが今後増えるのはあまりうれしくないと思います

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 6, 2026

ApAudienceService も正常に読み込まれていないserviceのひとつだけど、以下のように極限にシンプルな実装に書き換えると読み込まれるようになる

before

import { Injectable } from '@nestjs/common';
import promiseLimit from 'promise-limit';
import type { MiRemoteUser, MiUser } from '@/models/User.js';
import { concat, unique } from '@/misc/prelude/array.js';
import { bindThis } from '@/decorators.js';
import { getApIds } from './type.js';
import { ApPersonService } from './models/ApPersonService.js';
import type { ApObject } from './type.js';
import type { Resolver } from './ApResolverService.js';

type Visibility = 'public' | 'home' | 'followers' | 'specified';

type AudienceInfo = {
	visibility: Visibility,
	mentionedUsers: MiUser[],
	visibleUsers: MiUser[],
};

type GroupedAudience = Record<'public' | 'followers' | 'other', string[]>;

@Injectable()
export class ApAudienceService {
	constructor(
		private apPersonService: ApPersonService,
	) {
	}

	@bindThis
	public async parseAudience(actor: MiRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver): Promise<AudienceInfo> {
		const toGroups = this.groupingAudience(getApIds(to), actor);
		const ccGroups = this.groupingAudience(getApIds(cc), actor);

		const others = unique(concat([toGroups.other, ccGroups.other]));

		const limit = promiseLimit<MiUser | null>(2);
		const mentionedUsers = (await Promise.all(
			others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
		)).filter(x => x != null);

		if (toGroups.public.length > 0) {
			return {
				visibility: 'public',
				mentionedUsers,
				visibleUsers: [],
			};
		}

		if (ccGroups.public.length > 0) {
			return {
				visibility: 'home',
				mentionedUsers,
				visibleUsers: [],
			};
		}

		if (toGroups.followers.length > 0 || ccGroups.followers.length > 0) {
			return {
				visibility: 'followers',
				mentionedUsers,
				visibleUsers: [],
			};
		}

		return {
			visibility: 'specified',
			mentionedUsers,
			visibleUsers: mentionedUsers,
		};
	}

	@bindThis
	private groupingAudience(ids: string[], actor: MiRemoteUser): GroupedAudience {
		const groups: GroupedAudience = {
			public: [],
			followers: [],
			other: [],
		};

		for (const id of ids) {
			if (this.isPublic(id)) {
				groups.public.push(id);
			} else if (this.isFollowers(id, actor)) {
				groups.followers.push(id);
			} else {
				groups.other.push(id);
			}
		}

		groups.other = unique(groups.other);

		return groups;
	}

	@bindThis
	private isPublic(id: string): boolean {
		return [
			'https://www.w3.org/ns/activitystreams#Public',
			'as:Public',
			'Public',
		].includes(id);
	}

	@bindThis
	private isFollowers(id: string, actor: MiRemoteUser): boolean {
		return id === (actor.followersUri ?? `${actor.uri}/followers`);
	}
}

after

import { Injectable } from '@nestjs/common';
import type { MiRemoteUser } from '@/models/User.js';
import { bindThis } from '@/decorators.js';
import type { ApObject } from './type.js';
import type { Resolver } from './ApResolverService.js';

@Injectable()
export class ApAudienceService {
	constructor(
	) {
		console.log('ApAudienceService initialized');
	}

	@bindThis
	public async parseAudience(actor: MiRemoteUser, to?: ApObject, cc?: ApObject, resolver?: Resolver) {
		return {
			visibility: 'specified',
		};
	}
}

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

InstanceEntityServiceだけ読み込まれてないかも

コードに出てないわけでなさそう(ビルド成果物を検索したらヒットした)

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

kakkokari-gtyih commented Jan 6, 2026

バンドルでesmoduleそのままだと発生しない循環参照問題が発生するなら minify だけにしたい気がしてます。今後devなら問題ないのにbuildすると謎フリーズが今後増えるのはあまりうれしくないと思います

そもそもnestjsはバンドルされた環境で動かすことは想定されてるのかしら

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Jan 22, 2026

そもそもnestjsはバンドルされた環境で動かすことは想定されてるのかしら

Webpackを使用する場合の設定方法が書いてあったからされてそう

image

https://docs.nestjs.com/fundamentals/lazy-loading-modules

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

backendの開発サーバーをrolldown制御に変更した

@kakkokari-gtyih kakkokari-gtyih marked this pull request as ready for review April 16, 2026 01:31
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Apr 16, 2026
@kakkokari-gtyih kakkokari-gtyih changed the title enhance(backend): bundle backend using Rolldown (experimental) enhance(backend): bundle backend using Rolldown Apr 16, 2026
@syuilo syuilo merged commit 37bfcb6 into misskey-dev:develop Apr 16, 2026
40 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in [実験中] 管理用 Apr 16, 2026
@syuilo
Copy link
Copy Markdown
Member

syuilo commented Apr 16, 2026

👍🏻👍🏻

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Apr 16, 2026

pnpm devでエラー出るかも
image

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

Nodeがv24で起動してそうだけどv22にしても発生するかしら

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

ちなみにこちらの環境だと正常に起動している

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Apr 16, 2026

Windows?

@anatawa12
Copy link
Copy Markdown
Member

anatawa12 commented Apr 16, 2026

windows native環境でだけ発生する問題化も?(wsl linux macosじゃ発生しないかも

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

rolldown.config.ts の backendProcess = execaNode('./built/entry.js', { となっているところを backendProcess = execaNode('./built/entry.js', [], { に変えてみていけるか見てほしい

@syuilo
Copy link
Copy Markdown
Member

syuilo commented Apr 16, 2026

変わらなかった

@kakkokari-gtyih
Copy link
Copy Markdown
Contributor Author

なにがだめかわかったかも

m10i-0nyx pushed a commit to foundation0-link/misskey that referenced this pull request Apr 28, 2026
* enhance(backend): bundle backend using rolldown

* fix

* fix [ci skip]

* remove unused build script

* fix

* enhance: 起動からlistenまでかかる時間を減らす (MisskeyIO#1410)

* ✌️

* fix

* update rolldown

* fix(backend): extract static error classes to avoid rolldown design:paramtypes omission

* update rolldown

* Revert "fix(backend): extract static error classes to avoid rolldown design:paramtypes omission"

This reverts commit e2243c9.

* fix

* perf: avoid generating sourcemap in production

* fix

* fix

* fix

* fix paths

* fix

* fix

* fix

* fix

* fix

* enhance: バックエンドの開発サーバー制御をrolldown側で行うように

* remove nodemon

* Update Changelog

* tweak config

* fix

* fix

* fix

* clean up

---------

Co-authored-by: あわわわとーにゅ <[email protected]>
Co-authored-by: bab <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

packages/backend:test packages/backend Server side specific issue/PR packages/frontend Client side specific issue/PR size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

Development

Successfully merging this pull request may close these issues.

バックエンドのコードもbundle+minifyする

6 participants