diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs
index ad36deace3..2fdadaf9cb 100644
--- a/apps/web/next.config.mjs
+++ b/apps/web/next.config.mjs
@@ -7,14 +7,15 @@ import { withSentryConfig } from '@sentry/nextjs';
import SentryWebpackPlugin from '@sentry/webpack-plugin';
import debugLocal from 'next-debug-local';
-import preset from './preset.config.mjs';
+import { blockSuiteFeatureFlags, buildFlags } from './preset.config.mjs';
import { getCommitHash, getGitVersion } from './scripts/gitInfo.mjs';
const require = createRequire(import.meta.url);
const { createVanillaExtractPlugin } = require('@vanilla-extract/next-plugin');
const withVanillaExtract = createVanillaExtractPlugin();
-console.info('Runtime Preset', preset);
+console.info('Build Flags', buildFlags);
+console.info('Editor Flags', blockSuiteFeatureFlags);
const enableDebugLocal = path.isAbsolute(process.env.LOCAL_BLOCK_SUITE ?? '');
@@ -98,7 +99,8 @@ const nextConfig = {
profileTarget[process.env.API_SERVER_PROFILE || 'dev'] ??
profileTarget.dev,
editorVersion: require('./package.json').dependencies['@blocksuite/editor'],
- ...preset,
+ editorFlags: blockSuiteFeatureFlags,
+ ...buildFlags,
},
webpack: (config, { dev, isServer }) => {
config.experiments = { ...config.experiments, topLevelAwait: true };
@@ -144,7 +146,9 @@ const nextConfig = {
},
basePath: process.env.NEXT_BASE_PATH,
assetPrefix: process.env.NEXT_ASSET_PREFIX,
- pageExtensions: [...(preset.enableDebugPage ? ['tsx', 'dev.tsx'] : ['tsx'])],
+ pageExtensions: [
+ ...(buildFlags.enableDebugPage ? ['tsx', 'dev.tsx'] : ['tsx']),
+ ],
};
const baseDir = process.env.LOCAL_BLOCK_SUITE ?? '/';
diff --git a/apps/web/preset.config.mjs b/apps/web/preset.config.mjs
index 2a47a8ad7f..ac5d2a0671 100644
--- a/apps/web/preset.config.mjs
+++ b/apps/web/preset.config.mjs
@@ -1,6 +1,23 @@
+// @ts-check
import 'dotenv/config';
-const config = {
+/**
+ * @type {import('@affine/env').BlockSuiteFeatureFlags}
+ */
+export const blockSuiteFeatureFlags = {
+ enable_database: true,
+ enable_slash_menu: true,
+ enable_edgeless_toolbar: true,
+ enable_block_hub: true,
+ enable_drag_handle: true,
+ enable_surface: true,
+ enable_linked_page: true,
+};
+
+/**
+ * @type {import('@affine/env').BuildFlags}
+ */
+export const buildFlags = {
enableLegacyCloud: process.env.ENABLE_LEGACY_PROVIDER
? process.env.ENABLE_LEGACY_PROVIDER === 'true'
: true,
@@ -11,4 +28,3 @@ const config = {
process.env.ENABLE_DEBUG_PAGE ?? process.env.NODE_ENV === 'development'
),
};
-export default config;
diff --git a/apps/web/src/atoms/public-workspace/index.ts b/apps/web/src/atoms/public-workspace/index.ts
index 7567db3c59..2b9b412ff5 100644
--- a/apps/web/src/atoms/public-workspace/index.ts
+++ b/apps/web/src/atoms/public-workspace/index.ts
@@ -1,3 +1,5 @@
+import type { BlockSuiteFeatureFlags } from '@affine/env';
+import { config } from '@affine/env';
import type { AffinePublicWorkspace } from '@affine/workspace/type';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
@@ -23,11 +25,14 @@ function createPublicWorkspace(
blockSuiteWorkspace.doc,
new Uint8Array(binary)
);
+ Object.entries(config.editorFlags).forEach(([key, value]) => {
+ blockSuiteWorkspace.awarenessStore.setFlag(
+ key as keyof BlockSuiteFeatureFlags,
+ value
+ );
+ });
+ // force disable some features
blockSuiteWorkspace.awarenessStore.setFlag('enable_block_hub', false);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_set_remote_flag', false);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_database', false);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_edgeless_toolbar', false);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_slash_menu', false);
blockSuiteWorkspace.awarenessStore.setFlag('enable_drag_handle', false);
return {
flavour: WorkspaceFlavour.PUBLIC,
diff --git a/apps/web/src/pages/public-workspace/[workspaceId].tsx b/apps/web/src/pages/public-workspace/[workspaceId].tsx
index 0757d94873..ff040605d3 100644
--- a/apps/web/src/pages/public-workspace/[workspaceId].tsx
+++ b/apps/web/src/pages/public-workspace/[workspaceId].tsx
@@ -47,9 +47,6 @@ const ListPageInner: React.FC<{
},
[router, workspaceId]
);
- useEffect(() => {
- blockSuiteWorkspace.awarenessStore.setFlag('enable_block_hub', false);
- }, [blockSuiteWorkspace]);
const [name] = useBlockSuiteWorkspaceName(blockSuiteWorkspace);
const [avatar] = useBlockSuiteWorkspaceAvatarUrl(blockSuiteWorkspace);
const setSearchModalOpen = useSetAtom(openQuickSearchModalAtom);
diff --git a/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx b/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx
index 48043e3a39..18c2942293 100644
--- a/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx
+++ b/apps/web/src/pages/workspace/[workspaceId]/[pageId].tsx
@@ -1,3 +1,5 @@
+import type { BlockSuiteFeatureFlags } from '@affine/env';
+import { config } from '@affine/env';
import { useTranslation } from '@affine/i18n';
import { rootCurrentPageIdAtom } from '@affine/workspace/atom';
import { WorkspaceFlavour } from '@affine/workspace/type';
@@ -25,15 +27,13 @@ import { WorkspaceLayout } from '../../../layouts/workspace-layout';
import { WorkspacePlugins } from '../../../plugins';
import type { BlockSuiteWorkspace, NextPageWithLayout } from '../../../shared';
-function enableFullFlags(blockSuiteWorkspace: BlockSuiteWorkspace) {
- blockSuiteWorkspace.awarenessStore.setFlag('enable_set_remote_flag', false);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_database', false);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_slash_menu', true);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_edgeless_toolbar', true);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_block_hub', true);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_drag_handle', true);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_surface', true);
- blockSuiteWorkspace.awarenessStore.setFlag('enable_linked_page', true);
+function setEditorFlags(blockSuiteWorkspace: BlockSuiteWorkspace) {
+ Object.entries(config.editorFlags).forEach(([key, value]) => {
+ blockSuiteWorkspace.awarenessStore.setFlag(
+ key as keyof BlockSuiteFeatureFlags,
+ value
+ );
+ });
}
const WorkspaceDetail: React.FC = () => {
@@ -82,7 +82,7 @@ const WorkspaceDetail: React.FC = () => {
useEffect(() => {
if (currentWorkspace) {
- enableFullFlags(currentWorkspace.blockSuiteWorkspace);
+ setEditorFlags(currentWorkspace.blockSuiteWorkspace);
}
}, [currentWorkspace]);
if (!currentPageId) {
diff --git a/packages/component/.storybook/main.ts b/packages/component/.storybook/main.ts
index ae0fd35741..7265867ea6 100644
--- a/packages/component/.storybook/main.ts
+++ b/packages/component/.storybook/main.ts
@@ -31,6 +31,9 @@ export default {
},
resolve: {
alias: {
+ 'dotenv/config': fileURLToPath(
+ new URL('../../../scripts/vitest/dotenv-config.ts', import.meta.url)
+ ),
'next/config': fileURLToPath(
new URL(
'../../../scripts/vitest/next-config-mock.ts',
diff --git a/packages/env/src/config.ts b/packages/env/src/config.ts
index 154e38c4ff..8d97eb795b 100644
--- a/packages/env/src/config.ts
+++ b/packages/env/src/config.ts
@@ -1,30 +1,45 @@
+///
import { assertEquals } from '@blocksuite/global/utils';
import getConfig from 'next/config';
import { z } from 'zod';
import { getUaHelper } from './ua-helper';
-export const publicRuntimeConfigSchema = z.object({
+export const buildFlagsSchema = z.object({
+ enableBroadCastChannelProvider: z.boolean(),
+ enableDebugPage: z.boolean(),
+ enableLegacyCloud: z.boolean(),
+});
+
+export const blockSuiteFeatureFlags = z.object({
+ enable_database: z.boolean(),
+ enable_drag_handle: z.boolean(),
+ enable_surface: z.boolean(),
+ enable_block_hub: z.boolean(),
+ enable_slash_menu: z.boolean(),
+ enable_edgeless_toolbar: z.boolean(),
+ enable_linked_page: z.boolean(),
+});
+
+export type BlockSuiteFeatureFlags = z.infer;
+
+export type BuildFlags = z.infer;
+
+export const publicRuntimeConfigSchema = buildFlagsSchema.extend({
PROJECT_NAME: z.string(),
BUILD_DATE: z.string(),
gitVersion: z.string(),
hash: z.string(),
serverAPI: z.string(),
editorVersion: z.string(),
- enableBroadCastChannelProvider: z.boolean(),
- enableDebugPage: z.boolean(),
- enableLegacyCloud: z.boolean(),
+ editorFlags: blockSuiteFeatureFlags,
});
export type PublicRuntimeConfig = z.infer;
-const { publicRuntimeConfig: config } =
- getConfig() ??
- ({
- publicRuntimeConfig: {},
- } as {
- publicRuntimeConfig: PublicRuntimeConfig;
- });
+const { publicRuntimeConfig: config } = getConfig() as {
+ publicRuntimeConfig: PublicRuntimeConfig;
+};
publicRuntimeConfigSchema.parse(config);
diff --git a/scripts/vitest/dotenv-config.ts b/scripts/vitest/dotenv-config.ts
new file mode 100644
index 0000000000..08d8673a1a
--- /dev/null
+++ b/scripts/vitest/dotenv-config.ts
@@ -0,0 +1,2 @@
+// do nothing
+export {};
diff --git a/scripts/vitest/next-config-mock.ts b/scripts/vitest/next-config-mock.ts
index a80e7094ec..aebfed4a5d 100644
--- a/scripts/vitest/next-config-mock.ts
+++ b/scripts/vitest/next-config-mock.ts
@@ -1,3 +1,8 @@
+import {
+ blockSuiteFeatureFlags,
+ buildFlags,
+} from '../../apps/web/preset.config.mjs';
+
export default function getConfig() {
return {
publicRuntimeConfig: {
@@ -7,9 +12,8 @@ export default function getConfig() {
hash: 'UNKNOWN',
editorVersion: 'UNKNOWN',
serverAPI: 'http://127.0.0.1:3000/',
- enableLegacyCloud: true,
- enableBroadCastChannelProvider: true,
- enableDebugPage: true,
+ editorFlags: blockSuiteFeatureFlags,
+ ...buildFlags,
},
};
}