refactor!: remove next.js
(#3267)
@ -10,7 +10,7 @@
|
||||
"tasks": {
|
||||
"start-web": {
|
||||
"name": "Start Web",
|
||||
"command": "yarn nx dev @affine/web --port 8080",
|
||||
"command": "yarn dev-core",
|
||||
"runAtStart": true,
|
||||
"preview": {
|
||||
"port": 8080
|
||||
|
2
.github/deployment/front/Dockerfile
vendored
@ -1,6 +1,6 @@
|
||||
FROM openresty/openresty:1.21.4.1-0-buster
|
||||
WORKDIR /app
|
||||
COPY ./apps/web/out ./dist
|
||||
COPY ./apps/core/dist ./dist
|
||||
COPY ./.github/deployment/front/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
|
||||
COPY ./.github/deployment/front/affine.nginx.conf /etc/nginx/conf.d/affine.nginx.conf
|
||||
|
||||
|
42
.github/workflows/build.yml
vendored
@ -101,8 +101,8 @@ jobs:
|
||||
path: ./apps/storybook/storybook-static
|
||||
if-no-files-found: error
|
||||
|
||||
build-web:
|
||||
name: Build @affine/web
|
||||
build-core:
|
||||
name: Build @affine/core
|
||||
runs-on: ubuntu-latest
|
||||
environment: development
|
||||
|
||||
@ -110,13 +110,13 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
uses: ./.github/actions/setup-node
|
||||
- name: Build Web
|
||||
run: yarn nx build @affine/web
|
||||
- name: Upload artifact
|
||||
- name: Build Core
|
||||
run: yarn nx build @affine/core
|
||||
- name: Upload core artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: next-js-static
|
||||
path: ./apps/web/out
|
||||
name: core
|
||||
path: ./apps/core/dist
|
||||
if-no-files-found: error
|
||||
|
||||
server-test:
|
||||
@ -215,7 +215,7 @@ jobs:
|
||||
matrix:
|
||||
shard: [1, 2, 3, 4, 5]
|
||||
environment: development
|
||||
needs: build-web
|
||||
needs: build-core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -224,11 +224,11 @@ jobs:
|
||||
with:
|
||||
playwright-install: true
|
||||
electron-install: false
|
||||
- name: Download artifact
|
||||
- name: Download core artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: next-js-static
|
||||
path: ./apps/web/out
|
||||
name: core
|
||||
path: ./apps/core/dist
|
||||
|
||||
- name: Run playwright tests
|
||||
run: yarn e2e --forbid-only --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
||||
@ -260,7 +260,7 @@ jobs:
|
||||
name: E2E Migration Test
|
||||
runs-on: ubuntu-latest
|
||||
environment: development
|
||||
needs: [build-web]
|
||||
needs: build-core
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@ -270,11 +270,11 @@ jobs:
|
||||
playwright-install: true
|
||||
electron-install: false
|
||||
|
||||
- name: Download next static
|
||||
- name: Download core artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: next-js-static
|
||||
path: ./apps/web/out
|
||||
name: core
|
||||
path: ./apps/core/dist
|
||||
|
||||
- name: Unzip
|
||||
run: yarn unzip
|
||||
@ -333,7 +333,7 @@ jobs:
|
||||
target: x86_64-pc-windows-msvc,
|
||||
test: true,
|
||||
}
|
||||
needs: [build-web]
|
||||
needs: build-core
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js
|
||||
@ -353,10 +353,10 @@ jobs:
|
||||
env:
|
||||
NATIVE_TEST: 'true'
|
||||
|
||||
- name: Download static resource artifact
|
||||
- name: Download core artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: next-js-static
|
||||
name: core
|
||||
path: apps/electron/resources/web-static
|
||||
|
||||
- name: Build Plugins
|
||||
@ -443,11 +443,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download next static
|
||||
- name: Download core artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: next-js-static
|
||||
path: ./apps/web/out
|
||||
name: core
|
||||
path: ./apps/core/dist
|
||||
- name: Download server dist
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
|
4
.github/workflows/nightly-build.yml
vendored
@ -62,10 +62,10 @@ jobs:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
RELEASE_VERSION: ${{ needs.set-build-version.outputs.version }}
|
||||
|
||||
- name: Upload Artifact (web-static)
|
||||
- name: Upload core artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: before-make-web-static
|
||||
name: core
|
||||
path: apps/electron/resources/web-static
|
||||
|
||||
make-distribution:
|
||||
|
6
.github/workflows/release-desktop-app.yml
vendored
@ -66,10 +66,10 @@ jobs:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
RELEASE_VERSION: ${{ github.event.inputs.version || steps.get-canary-version.outputs.RELEASE_VERSION }}
|
||||
|
||||
- name: Upload Artifact (web-static)
|
||||
- name: Upload core artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: before-make-web-static
|
||||
name: core
|
||||
path: apps/electron/resources/web-static
|
||||
|
||||
make-distribution:
|
||||
@ -120,7 +120,7 @@ jobs:
|
||||
nx_token: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: before-make-web-static
|
||||
name: core
|
||||
path: apps/electron/resources/web-static
|
||||
|
||||
- name: Build Plugins
|
||||
|
1
.gitignore
vendored
@ -13,6 +13,7 @@
|
||||
/out-tsc
|
||||
.nyc_output
|
||||
.coverage
|
||||
.swc
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
|
84
apps/core/.webpack/cache-group.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { hash } from './utils.js';
|
||||
|
||||
function testPackageName(regexp: RegExp): (module: any) => boolean {
|
||||
return (module: any) =>
|
||||
module.nameForCondition && regexp.test(module.nameForCondition());
|
||||
}
|
||||
|
||||
export const productionCacheGroups = {
|
||||
asyncVendor: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name(module: any) {
|
||||
// https://hackernoon.com/the-100-correct-way-to-split-your-chunks-with-webpack-f8a9df5b7758
|
||||
const name =
|
||||
module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)?.[1] ??
|
||||
'unknown';
|
||||
return `npm-async-${hash(name)}`;
|
||||
},
|
||||
priority: Number.MAX_SAFE_INTEGER,
|
||||
chunks: 'async' as const,
|
||||
},
|
||||
mui: {
|
||||
name: `npm-mui`,
|
||||
test: testPackageName(/[\\/]node_modules[\\/](mui|@mui)[\\/]/),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
blocksuite: {
|
||||
name: `npm-blocksuite`,
|
||||
test: testPackageName(/[\\/]node_modules[\\/](@blocksuite)[\\/]/),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
react: {
|
||||
name: `npm-react`,
|
||||
test: testPackageName(
|
||||
/[\\/]node_modules[\\/](react|react-dom|scheduler)[\\/]/
|
||||
),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
jotai: {
|
||||
name: `npm-jotai`,
|
||||
test: testPackageName(/[\\/]node_modules[\\/](jotai)[\\/]/),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
rxjs: {
|
||||
name: `npm-rxjs`,
|
||||
test: testPackageName(/[\\/]node_modules[\\/]rxjs[\\/]/),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
lodash: {
|
||||
name: `npm-lodash`,
|
||||
test: testPackageName(/[\\/]node_modules[\\/]lodash[\\/]/),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
emotion: {
|
||||
name: `npm-emotion`,
|
||||
test: testPackageName(/[\\/]node_modules[\\/](@emotion)[\\/]/),
|
||||
priority: 200,
|
||||
enforce: true,
|
||||
},
|
||||
vendor: {
|
||||
name: 'vendor',
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: 190,
|
||||
enforce: true,
|
||||
},
|
||||
styles: {
|
||||
name: 'styles',
|
||||
test: (module: any) =>
|
||||
module.nameForCondition &&
|
||||
/\.css$/.test(module.nameForCondition()) &&
|
||||
!/^javascript/.test(module.type),
|
||||
chunks: 'all' as const,
|
||||
minSize: 1,
|
||||
minChunks: 1,
|
||||
reuseExistingChunk: true,
|
||||
priority: 1000,
|
||||
enforce: true,
|
||||
},
|
||||
};
|
306
apps/core/.webpack/config.ts
Normal file
@ -0,0 +1,306 @@
|
||||
import { join, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createRequire } from 'node:module';
|
||||
import HTMLPlugin from 'html-webpack-plugin';
|
||||
import type { Configuration as DevServerConfiguration } from 'webpack-dev-server';
|
||||
import { PerfseePlugin } from '@perfsee/webpack';
|
||||
import { sentryWebpackPlugin } from '@sentry/webpack-plugin';
|
||||
|
||||
import CopyPlugin from 'copy-webpack-plugin';
|
||||
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import webpack from 'webpack';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
|
||||
import { productionCacheGroups } from './cache-group.js';
|
||||
import type { BuildFlags } from '@affine/cli/config';
|
||||
import { projectRoot } from '@affine/cli/config';
|
||||
import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin';
|
||||
import { computeCacheKey } from './utils.js';
|
||||
import type { RuntimeConfig } from '@affine/env/global';
|
||||
|
||||
const IN_CI = !!process.env.CI;
|
||||
|
||||
export const rootPath = fileURLToPath(new URL('..', import.meta.url));
|
||||
|
||||
const require = createRequire(rootPath);
|
||||
|
||||
const OptimizeOptionOptions: (
|
||||
buildFlags: BuildFlags
|
||||
) => webpack.Configuration['optimization'] = buildFlags => ({
|
||||
minimize: buildFlags.mode === 'production',
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: TerserPlugin.swcMinify,
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
terserOptions: {
|
||||
ecma: 2020,
|
||||
compress: {
|
||||
unused: true,
|
||||
},
|
||||
mangle: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
removeEmptyChunks: true,
|
||||
providedExports: true,
|
||||
usedExports: true,
|
||||
sideEffects: true,
|
||||
removeAvailableModules: true,
|
||||
runtimeChunk: {
|
||||
name: 'runtime',
|
||||
},
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
minSize: 1,
|
||||
minChunks: 1,
|
||||
maxInitialRequests: Number.MAX_SAFE_INTEGER,
|
||||
maxAsyncRequests: Number.MAX_SAFE_INTEGER,
|
||||
cacheGroups:
|
||||
buildFlags.mode === 'production'
|
||||
? productionCacheGroups
|
||||
: {
|
||||
default: false,
|
||||
vendors: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const createConfiguration: (
|
||||
buildFlags: BuildFlags,
|
||||
runtimeConfig: RuntimeConfig
|
||||
) => webpack.Configuration = (buildFlags, runtimeConfig) => {
|
||||
let publicPath = process.env.PUBLIC_PATH ?? '/';
|
||||
|
||||
const cacheKey = computeCacheKey(buildFlags);
|
||||
|
||||
const config = {
|
||||
name: 'affine',
|
||||
// to set a correct base path for the source map
|
||||
context: projectRoot,
|
||||
output: {
|
||||
environment: {
|
||||
module: true,
|
||||
dynamicImport: true,
|
||||
},
|
||||
filename: 'js/[name].js',
|
||||
// In some cases webpack will emit files starts with "_" which is reserved in web extension.
|
||||
chunkFilename: 'js/chunk.[name].js',
|
||||
assetModuleFilename: 'assets/[hash][ext][query]',
|
||||
devtoolModuleFilenameTemplate: 'webpack://[namespace]/[resource-path]',
|
||||
hotUpdateChunkFilename: 'hot/[id].[fullhash].js',
|
||||
hotUpdateMainFilename: 'hot/[runtime].[fullhash].json',
|
||||
path: join(rootPath, 'dist'),
|
||||
clean: buildFlags.mode === 'production',
|
||||
globalObject: 'globalThis',
|
||||
publicPath,
|
||||
},
|
||||
target: ['web', 'es2022'],
|
||||
|
||||
mode: buildFlags.mode,
|
||||
|
||||
devtool:
|
||||
buildFlags.mode === 'production'
|
||||
? buildFlags.distribution === 'desktop'
|
||||
? 'inline-source-map'
|
||||
: 'hidden-nosources-source-map'
|
||||
: 'eval-cheap-module-source-map',
|
||||
|
||||
resolve: {
|
||||
extensionAlias: {
|
||||
'.js': ['.js', '.tsx', '.ts'],
|
||||
'.mjs': ['.mjs', '.mts'],
|
||||
},
|
||||
extensions: ['.js', '.ts', '.tsx'],
|
||||
},
|
||||
|
||||
cache: {
|
||||
type: 'filesystem',
|
||||
buildDependencies: {
|
||||
config: [fileURLToPath(import.meta.url)],
|
||||
},
|
||||
version: cacheKey,
|
||||
},
|
||||
|
||||
module: {
|
||||
parser: {
|
||||
javascript: {
|
||||
// Treat as missing export as error
|
||||
strictExportPresence: true,
|
||||
},
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js?$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
// Compile all ts files in the workspace
|
||||
include: resolve(rootPath, '..', '..'),
|
||||
loader: require.resolve('swc-loader'),
|
||||
options: {
|
||||
// https://swc.rs/docs/configuring-swc/
|
||||
jsc: {
|
||||
preserveAllComments: true,
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
dynamicImport: true,
|
||||
topLevelAwait: false,
|
||||
tsx: true,
|
||||
},
|
||||
target: 'es2022',
|
||||
externalHelpers: true,
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'automatic',
|
||||
refresh: buildFlags.mode === 'development' && {
|
||||
refreshReg: '$RefreshReg$',
|
||||
refreshSig: '$RefreshSig$',
|
||||
emitFullSignatures: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
experimental: {
|
||||
keepImportAssertions: true,
|
||||
plugins: [
|
||||
buildFlags.coverage && [
|
||||
'swc-plugin-coverage-instrument',
|
||||
{},
|
||||
],
|
||||
].filter(Boolean),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
'thread-loader',
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
icon: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: [/node_modules/],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif|svg|webp)$/,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)$/i,
|
||||
type: 'asset/resource',
|
||||
},
|
||||
{
|
||||
test: /\.txt$/,
|
||||
loader: 'raw-loader',
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
url: false,
|
||||
sourceMap: false,
|
||||
modules: false,
|
||||
import: true,
|
||||
importLoaders: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
postcssOptions: {
|
||||
config: resolve(
|
||||
rootPath,
|
||||
'.webpack',
|
||||
'postcss.config.cjs'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
...(IN_CI ? [] : [new webpack.ProgressPlugin({ percentBy: 'entries' })]),
|
||||
...(buildFlags.mode === 'development'
|
||||
? [new ReactRefreshWebpackPlugin({ overlay: false, esModule: true })]
|
||||
: []),
|
||||
new HTMLPlugin({
|
||||
template: join(rootPath, '.webpack', 'template.html'),
|
||||
inject: 'body',
|
||||
scriptLoading: 'defer',
|
||||
minify: false,
|
||||
chunks: ['index'],
|
||||
filename: 'index.html',
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: `[name].[chunkhash:8].css`,
|
||||
ignoreOrder: true,
|
||||
}),
|
||||
new VanillaExtractPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': JSON.stringify({}),
|
||||
runtimeConfig: JSON.stringify(runtimeConfig),
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: resolve(rootPath, 'public'), to: resolve(rootPath, 'dist') },
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
optimization: OptimizeOptionOptions(buildFlags),
|
||||
|
||||
devServer: {
|
||||
hot: 'only',
|
||||
liveReload: false,
|
||||
client: undefined,
|
||||
historyApiFallback: true,
|
||||
static: {
|
||||
directory: resolve(rootPath, 'public'),
|
||||
publicPath: '/',
|
||||
},
|
||||
} as DevServerConfiguration,
|
||||
} satisfies webpack.Configuration;
|
||||
|
||||
if (buildFlags.mode === 'production' && process.env.PERFSEE_TOKEN) {
|
||||
config.devtool = 'hidden-nosources-source-map';
|
||||
config.plugins.push(
|
||||
new PerfseePlugin({
|
||||
project: 'affine-toeverything',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
process.env.SENTRY_AUTH_TOKEN &&
|
||||
process.env.SENTRY_ORG &&
|
||||
process.env.SENTRY_PROJECT
|
||||
) {
|
||||
config.plugins.push(
|
||||
sentryWebpackPlugin({
|
||||
org: process.env.SENTRY_ORG,
|
||||
project: process.env.SENTRY_PROJECT,
|
||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
20
apps/core/.webpack/postcss.config.cjs
Normal file
@ -0,0 +1,20 @@
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
module.exports = function (context) {
|
||||
const plugins = [
|
||||
cssnano({
|
||||
preset: [
|
||||
'default',
|
||||
{
|
||||
convertValues: false,
|
||||
},
|
||||
],
|
||||
}),
|
||||
];
|
||||
|
||||
return {
|
||||
from: context.from,
|
||||
plugins,
|
||||
to: context.to,
|
||||
};
|
||||
};
|
115
apps/core/.webpack/runtime-config.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import type { BlockSuiteFeatureFlags, RuntimeConfig } from '@affine/env/global';
|
||||
import type { BuildFlags } from '@affine/cli/config';
|
||||
import { createRequire } from 'node:module';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
const editorFlags: 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,
|
||||
enable_bookmark_operation: false,
|
||||
};
|
||||
|
||||
export function getRuntimeConfig(buildFlags: BuildFlags): RuntimeConfig {
|
||||
const buildPreset: Record<string, RuntimeConfig> = {
|
||||
stable: {
|
||||
enablePlugin: false,
|
||||
enableTestProperties: false,
|
||||
enableBroadcastChannelProvider: true,
|
||||
enableDebugPage: true,
|
||||
changelogUrl: 'https://affine.pro/blog/what-is-new-affine-0717',
|
||||
imageProxyUrl: 'https://workers.toeverything.workers.dev/proxy/image',
|
||||
enablePreloading: true,
|
||||
enableNewSettingModal: true,
|
||||
enableNewSettingUnstableApi: false,
|
||||
enableSQLiteProvider: true,
|
||||
enableMoveDatabase: false,
|
||||
enableNotificationCenter: false,
|
||||
enableCloud: false,
|
||||
serverAPI: 'https://localhost:3010',
|
||||
editorFlags,
|
||||
appVersion: packageJson.version,
|
||||
editorVersion: packageJson.dependencies['@blocksuite/editor'],
|
||||
},
|
||||
// canary will be aggressive and enable all features
|
||||
canary: {
|
||||
enablePlugin: true,
|
||||
enableTestProperties: true,
|
||||
enableBroadcastChannelProvider: true,
|
||||
enableDebugPage: true,
|
||||
changelogUrl: 'https://affine.pro/blog/what-is-new-affine-0717',
|
||||
imageProxyUrl: 'https://workers.toeverything.workers.dev/proxy/image',
|
||||
enablePreloading: true,
|
||||
enableNewSettingModal: true,
|
||||
enableNewSettingUnstableApi: false,
|
||||
enableSQLiteProvider: true,
|
||||
enableMoveDatabase: false,
|
||||
enableNotificationCenter: true,
|
||||
enableCloud: false,
|
||||
serverAPI: 'https://localhost:3010',
|
||||
editorFlags,
|
||||
appVersion: packageJson.version,
|
||||
editorVersion: packageJson.dependencies['@blocksuite/editor'],
|
||||
},
|
||||
};
|
||||
|
||||
// beta and internal versions are the same as stable
|
||||
buildPreset.beta = buildPreset.stable;
|
||||
buildPreset.internal = buildPreset.stable;
|
||||
|
||||
const currentBuild = buildFlags.channel;
|
||||
|
||||
if (!(currentBuild in buildPreset)) {
|
||||
throw new Error(`BUILD_TYPE ${currentBuild} is not supported`);
|
||||
}
|
||||
|
||||
const currentBuildPreset = buildPreset[currentBuild];
|
||||
|
||||
const environmentPreset = {
|
||||
enablePlugin: process.env.ENABLE_PLUGIN
|
||||
? process.env.ENABLE_PLUGIN === 'true'
|
||||
: currentBuildPreset.enablePlugin,
|
||||
enableTestProperties: process.env.ENABLE_TEST_PROPERTIES
|
||||
? process.env.ENABLE_TEST_PROPERTIES === 'true'
|
||||
: currentBuildPreset.enableTestProperties,
|
||||
enableBroadcastChannelProvider: process.env.ENABLE_BC_PROVIDER
|
||||
? process.env.ENABLE_BC_PROVIDER !== 'false'
|
||||
: currentBuildPreset.enableBroadcastChannelProvider,
|
||||
changelogUrl: process.env.CHANGELOG_URL ?? currentBuildPreset.changelogUrl,
|
||||
enablePreloading: process.env.ENABLE_PRELOADING
|
||||
? process.env.ENABLE_PRELOADING === 'true'
|
||||
: currentBuildPreset.enablePreloading,
|
||||
enableNewSettingModal: process.env.ENABLE_NEW_SETTING_MODAL
|
||||
? process.env.ENABLE_NEW_SETTING_MODAL === 'true'
|
||||
: currentBuildPreset.enableNewSettingModal,
|
||||
enableSQLiteProvider: process.env.ENABLE_SQLITE_PROVIDER
|
||||
? process.env.ENABLE_SQLITE_PROVIDER === 'true'
|
||||
: currentBuildPreset.enableSQLiteProvider,
|
||||
enableNewSettingUnstableApi: process.env.ENABLE_NEW_SETTING_UNSTABLE_API
|
||||
? process.env.ENABLE_NEW_SETTING_UNSTABLE_API === 'true'
|
||||
: currentBuildPreset.enableNewSettingUnstableApi,
|
||||
enableNotificationCenter: process.env.ENABLE_NOTIFICATION_CENTER
|
||||
? process.env.ENABLE_NOTIFICATION_CENTER === 'true'
|
||||
: currentBuildPreset.enableNotificationCenter,
|
||||
enableCloud: process.env.ENABLE_CLOUD
|
||||
? process.env.ENABLE_CLOUD === 'true'
|
||||
: currentBuildPreset.enableCloud,
|
||||
enableMoveDatabase: process.env.ENABLE_MOVE_DATABASE
|
||||
? process.env.ENABLE_MOVE_DATABASE === 'true'
|
||||
: currentBuildPreset.enableMoveDatabase,
|
||||
};
|
||||
|
||||
return {
|
||||
...currentBuildPreset,
|
||||
// environment preset will overwrite current build preset
|
||||
// this environment variable is for debug proposes only
|
||||
// do not put them into CI
|
||||
...(process.env.CI ? {} : environmentPreset),
|
||||
};
|
||||
}
|
45
apps/core/.webpack/template.html
Normal file
@ -0,0 +1,45 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1"
|
||||
/>
|
||||
<title>AFFiNE</title>
|
||||
<meta name="theme-color" content="#fafafa" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" sizes="192x192" href="/chrome-192x192.png" />
|
||||
<meta name="emotion-insertion-point" content="" />
|
||||
<meta property="description" content="{description}" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:url" content="https://app.affine.pro/" />
|
||||
<meta
|
||||
name="twitter:title"
|
||||
content="AFFiNE:There can be more than Notion and Miro."
|
||||
/>
|
||||
<meta name="twitter:description" content="{description}" />
|
||||
<meta name="twitter:site" content="@AffineOfficial" />
|
||||
<meta name="twitter:image" content="https://affine.pro/og.jpeg" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="AFFiNE:There can be more than Notion and Miro."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together."
|
||||
/>
|
||||
<meta property="og:url" content="https://app.affine.pro/" />
|
||||
<meta property="og:image" content="https://affine.pro/og.jpeg" />
|
||||
<link
|
||||
data-react-helmet="true"
|
||||
rel="shortcut icon"
|
||||
href="https://affine.pro/favicon.ico"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
18
apps/core/.webpack/utils.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import type { BuildFlags } from '@affine/cli/config';
|
||||
|
||||
export function hash(content: string): string {
|
||||
const hash = createHash('sha512');
|
||||
hash.update(content);
|
||||
const pkgHash = hash.digest('hex');
|
||||
return pkgHash.substring(0, 8);
|
||||
}
|
||||
|
||||
export function computeCacheKey(buildFlags: BuildFlags) {
|
||||
return [
|
||||
'1',
|
||||
'node' + process.version,
|
||||
buildFlags.mode,
|
||||
buildFlags.distribution,
|
||||
].join('-');
|
||||
}
|
23
apps/core/.webpack/webpack.config.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { createConfiguration, rootPath } from './config.js';
|
||||
import { merge } from 'webpack-merge';
|
||||
import { resolve } from 'node:path';
|
||||
import type { BuildFlags } from '@affine/cli/config';
|
||||
import { getRuntimeConfig } from './runtime-config.js';
|
||||
|
||||
export default async function (cli_env: any, _: any) {
|
||||
const flags: BuildFlags = JSON.parse(
|
||||
Buffer.from(cli_env.flags, 'hex').toString('utf-8')
|
||||
);
|
||||
console.log('build flags', flags);
|
||||
const runtimeConfig = getRuntimeConfig(flags);
|
||||
console.log('runtime config', runtimeConfig);
|
||||
const config = createConfiguration(flags, runtimeConfig);
|
||||
return merge(config, {
|
||||
entry: {
|
||||
index: {
|
||||
asyncChunks: true,
|
||||
import: resolve(rootPath, 'src/index.tsx'),
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
{
|
||||
"name": "@affine/web",
|
||||
"name": "@affine/core",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"version": "0.7.0-canary.47",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build && next export",
|
||||
"start": "NODE_ENV=development next start",
|
||||
"static-server": "ts-node-esm server.mts"
|
||||
"build": "yarn -T run build-core",
|
||||
"dev": "yarn -T run dev-core",
|
||||
"static-server": "ts-node-esm ./server.mts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@affine-test/fixtures": "workspace:*",
|
||||
"@affine/component": "workspace:*",
|
||||
"@affine/copilot": "workspace:*",
|
||||
"@affine/debug": "workspace:*",
|
||||
"@affine/env": "workspace:*",
|
||||
"@affine/graphql": "workspace:*",
|
||||
@ -34,23 +33,23 @@
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/material": "^5.13.6",
|
||||
"@react-hookz/web": "^23.1.0",
|
||||
"@sentry/nextjs": "^7.57.0",
|
||||
"@toeverything/hooks": "workspace:*",
|
||||
"@toeverything/infra": "workspace:*",
|
||||
"@toeverything/plugin-infra": "workspace:*",
|
||||
"async-call-rpc": "^6.3.1",
|
||||
"cmdk": "^0.2.0",
|
||||
"css-spring": "^4.1.0",
|
||||
"cssnano": "^6.0.1",
|
||||
"graphql": "^16.7.1",
|
||||
"jotai": "^2.2.2",
|
||||
"jotai-devtools": "^0.6.0",
|
||||
"lit": "^2.7.5",
|
||||
"lottie-web": "^5.12.2",
|
||||
"mini-css-extract-plugin": "^2.7.6",
|
||||
"next-themes": "^0.2.1",
|
||||
"postcss-loader": "^7.3.3",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-is": "^18.2.0",
|
||||
"react-is": "18.2.0",
|
||||
"react-resizable-panels": "^0.0.53",
|
||||
"react-router-dom": "^6.14.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"swr": "^2.1.5",
|
||||
"y-protocols": "^1.0.5",
|
||||
@ -59,30 +58,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@perfsee/webpack": "^1.8.2",
|
||||
"@redux-devtools/extension": "^3.2.5",
|
||||
"@rich-data/viewer": "^2.15.6",
|
||||
"@sentry/webpack-plugin": "^1.20.1",
|
||||
"@swc-jotai/debug-label": "^0.0.10",
|
||||
"@swc-jotai/react-refresh": "^0.0.8",
|
||||
"@types/react": "^18.2.14",
|
||||
"@types/react-dom": "^18.2.6",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
|
||||
"@sentry/webpack-plugin": "^2.4.0",
|
||||
"@svgr/webpack": "^8.0.1",
|
||||
"@swc/core": "^1.3.70",
|
||||
"@types/webpack-env": "^1.18.1",
|
||||
"@vanilla-extract/css": "^1.12.0",
|
||||
"@vanilla-extract/next-plugin": "=2.1.2",
|
||||
"dotenv": "^16.3.1",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-config-next": "^13.4.7",
|
||||
"eslint-plugin-unicorn": "^47.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"express": "^4.18.2",
|
||||
"next": "=13.4.2",
|
||||
"next-debug-local": "^0.1.5",
|
||||
"next-router-mock": "^0.9.7",
|
||||
"html-webpack-plugin": "^5.5.3",
|
||||
"raw-loader": "^4.0.2",
|
||||
"redux": "^4.2.1",
|
||||
"swc-plugin-coverage-instrument": "^0.0.18",
|
||||
"swc-loader": "^0.2.3",
|
||||
"swc-plugin-coverage-instrument": "^0.0.19",
|
||||
"thread-loader": "^4.0.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6",
|
||||
"webpack": "^5.88.1"
|
||||
},
|
||||
"stableVersion": "0.0.0"
|
||||
"webpack": "^5.88.1",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^4.15.1",
|
||||
"webpack-merge": "^5.9.0"
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@affine/web",
|
||||
"name": "@affine/core",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"root": "apps/web",
|
||||
"sourceRoot": "apps/web/src",
|
||||
"root": "apps/core",
|
||||
"sourceRoot": "apps/core/src",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-script",
|
||||
@ -12,26 +12,29 @@
|
||||
"{projectRoot}/**/*",
|
||||
"{workspaceRoot}/packages/component/src/**/*",
|
||||
"{workspaceRoot}/packages/debug/src/**/*",
|
||||
"{workspaceRoot}/packages/debug/graphql/**/*",
|
||||
"{workspaceRoot}/packages/graphql/src/**/*",
|
||||
"{workspaceRoot}/packages/hooks/src/**/*",
|
||||
"{workspaceRoot}/packages/jotai/src/**/*",
|
||||
"{workspaceRoot}/packages/templates/src/**/*",
|
||||
"{workspaceRoot}/packages/workspace/src/**/*",
|
||||
{
|
||||
"env": "BUILD_TYPE"
|
||||
},
|
||||
{
|
||||
"env": "PERFSEE_TOKEN"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"script": "build"
|
||||
},
|
||||
"outputs": ["{projectRoot}/out"]
|
||||
"outputs": ["{projectRoot}/dist"]
|
||||
},
|
||||
"dev": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "dev"
|
||||
},
|
||||
"outputs": ["{projectRoot}/.next"]
|
||||
"outputs": ["{projectRoot}/dist"]
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 710 KiB After Width: | Height: | Size: 710 KiB |
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 822 KiB After Width: | Height: | Size: 822 KiB |
Before Width: | Height: | Size: 363 KiB After Width: | Height: | Size: 363 KiB |
Before Width: | Height: | Size: 945 KiB After Width: | Height: | Size: 945 KiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 380 KiB After Width: | Height: | Size: 380 KiB |
Before Width: | Height: | Size: 6.8 MiB After Width: | Height: | Size: 6.8 MiB |
15
apps/core/server.mts
Normal file
@ -0,0 +1,15 @@
|
||||
// static server for web app
|
||||
import express from 'express';
|
||||
const app = express();
|
||||
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
app.use('/', express.static('dist'));
|
||||
|
||||
app.get('/*', (req, res) => {
|
||||
res.sendFile('index.html', { root: 'dist' });
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on port ${PORT}`);
|
||||
});
|
158
apps/core/src/app.tsx
Normal file
@ -0,0 +1,158 @@
|
||||
import '@affine/component/theme/global.css';
|
||||
import '@affine/component/theme/theme.css';
|
||||
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { WorkspaceFallback } from '@affine/component/workspace';
|
||||
import { createI18n, setUpLanguage } from '@affine/i18n';
|
||||
import { CacheProvider } from '@emotion/react';
|
||||
import type { RouterState } from '@remix-run/router';
|
||||
import {
|
||||
currentPageIdAtom,
|
||||
currentWorkspaceIdAtom,
|
||||
} from '@toeverything/plugin-infra/manager';
|
||||
import type { PropsWithChildren, ReactElement } from 'react';
|
||||
import { lazy, memo, Suspense, useEffect } from 'react';
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
|
||||
import { historyBaseAtom, MAX_HISTORY } from './atoms/history';
|
||||
import createEmotionCache from './utils/create-emotion-cache';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: '/',
|
||||
lazy: () => import('./pages/index'),
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
lazy: () => import('./pages/404'),
|
||||
},
|
||||
{
|
||||
path: '/workspace/:workspaceId/all',
|
||||
lazy: () => import('./pages/workspace/all-page'),
|
||||
},
|
||||
{
|
||||
path: '/workspace/:workspaceId/trash',
|
||||
lazy: () => import('./pages/workspace/trash-page'),
|
||||
},
|
||||
{
|
||||
path: '/workspace/:workspaceId/:pageId',
|
||||
lazy: () => import('./pages/workspace/detail-page'),
|
||||
},
|
||||
]);
|
||||
|
||||
//#region atoms bootstrap
|
||||
|
||||
currentWorkspaceIdAtom.onMount = set => {
|
||||
const callback = (state: RouterState) => {
|
||||
const value = state.location.pathname.split('/')[2];
|
||||
if (value) {
|
||||
set(value);
|
||||
localStorage.setItem('last_workspace_id', value);
|
||||
} else {
|
||||
set(null);
|
||||
}
|
||||
};
|
||||
callback(router.state);
|
||||
|
||||
const unsubscribe = router.subscribe(callback);
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
};
|
||||
|
||||
currentPageIdAtom.onMount = set => {
|
||||
const callback = (state: RouterState) => {
|
||||
const value = state.location.pathname.split('/')[3];
|
||||
if (value) {
|
||||
set(value);
|
||||
} else {
|
||||
set(null);
|
||||
}
|
||||
};
|
||||
callback(router.state);
|
||||
|
||||
const unsubscribe = router.subscribe(callback);
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
};
|
||||
|
||||
historyBaseAtom.onMount = set => {
|
||||
const unsubscribe = router.subscribe(state => {
|
||||
set(prev => {
|
||||
const url = state.location.pathname;
|
||||
console.log('push', url, prev.skip, prev.stack.length, prev.current);
|
||||
if (prev.skip) {
|
||||
return {
|
||||
stack: [...prev.stack],
|
||||
current: prev.current,
|
||||
skip: false,
|
||||
};
|
||||
} else {
|
||||
if (prev.current < prev.stack.length - 1) {
|
||||
const newStack = prev.stack.slice(0, prev.current);
|
||||
newStack.push(url);
|
||||
if (newStack.length > MAX_HISTORY) {
|
||||
newStack.shift();
|
||||
}
|
||||
return {
|
||||
stack: newStack,
|
||||
current: newStack.length - 1,
|
||||
skip: false,
|
||||
};
|
||||
} else {
|
||||
const newStack = [...prev.stack, url];
|
||||
if (newStack.length > MAX_HISTORY) {
|
||||
newStack.shift();
|
||||
}
|
||||
return {
|
||||
stack: newStack,
|
||||
current: newStack.length - 1,
|
||||
skip: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
};
|
||||
//#endregion
|
||||
|
||||
const i18n = createI18n();
|
||||
const cache = createEmotionCache();
|
||||
|
||||
const DevTools = lazy(() =>
|
||||
import('jotai-devtools').then(m => ({ default: m.DevTools }))
|
||||
);
|
||||
|
||||
const DebugProvider = ({ children }: PropsWithChildren): ReactElement => {
|
||||
return (
|
||||
<>
|
||||
<Suspense>{process.env.DEBUG_JOTAI === 'true' && <DevTools />}</Suspense>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const App = memo(function App() {
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = i18n.language;
|
||||
// todo(himself65): this is a hack, we should use a better way to set the language
|
||||
setUpLanguage(i18n)?.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<CacheProvider value={cache}>
|
||||
<AffineContext>
|
||||
<DebugProvider>
|
||||
<Suspense fallback={<WorkspaceFallback key="RootPageLoading" />}>
|
||||
<RouterProvider router={router} />
|
||||
</Suspense>
|
||||
</DebugProvider>
|
||||
</AffineContext>
|
||||
</CacheProvider>
|
||||
);
|
||||
});
|
52
apps/core/src/atoms/history.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { useAtom } from 'jotai';
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export type History = {
|
||||
stack: string[];
|
||||
current: number;
|
||||
skip: boolean;
|
||||
};
|
||||
|
||||
export const MAX_HISTORY = 50;
|
||||
|
||||
export const historyBaseAtom = atomWithStorage<History>('router-history', {
|
||||
stack: [],
|
||||
current: 0,
|
||||
skip: false,
|
||||
});
|
||||
|
||||
export function useHistoryAtom() {
|
||||
const navigate = useNavigate();
|
||||
const [base, setBase] = useAtom(historyBaseAtom);
|
||||
return [
|
||||
base,
|
||||
useCallback(
|
||||
(forward: boolean) => {
|
||||
setBase(prev => {
|
||||
if (forward) {
|
||||
const target = Math.min(prev.stack.length - 1, prev.current + 1);
|
||||
const url = prev.stack[target];
|
||||
navigate(url);
|
||||
return {
|
||||
...prev,
|
||||
current: target,
|
||||
skip: true,
|
||||
};
|
||||
} else {
|
||||
const target = Math.max(0, prev.current - 1);
|
||||
const url = prev.stack[target];
|
||||
navigate(url);
|
||||
return {
|
||||
...prev,
|
||||
current: target,
|
||||
skip: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
[setBase, navigate]
|
||||
),
|
||||
] as const;
|
||||
}
|
@ -12,14 +12,11 @@ import {
|
||||
} from '@toeverything/plugin-infra/manager';
|
||||
import { useAtomValue } from 'jotai/react';
|
||||
import { Provider } from 'jotai/react';
|
||||
import type { NextRouter } from 'next/router';
|
||||
import type { ErrorInfo, ReactElement, ReactNode } from 'react';
|
||||
import type React from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
export type AffineErrorBoundaryProps = React.PropsWithChildren<{
|
||||
router: NextRouter;
|
||||
}>;
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
export type AffineErrorBoundaryProps = React.PropsWithChildren;
|
||||
|
||||
type AffineError =
|
||||
| QueryParamError
|
||||
@ -32,13 +29,13 @@ interface AffineErrorBoundaryState {
|
||||
error: AffineError | null;
|
||||
}
|
||||
|
||||
export const DumpInfo = (props: Pick<AffineErrorBoundaryProps, 'router'>) => {
|
||||
const router = props.router;
|
||||
export const DumpInfo = () => {
|
||||
const location = useLocation();
|
||||
const metadata = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
|
||||
const currentPageId = useAtomValue(currentPageIdAtom);
|
||||
const path = router.asPath;
|
||||
const query = router.query;
|
||||
const path = location.pathname;
|
||||
const query = useParams();
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
@ -91,24 +88,6 @@ export class AffineErrorBoundary extends Component<
|
||||
Cannot find page {error.pageId} in workspace{' '}
|
||||
{error.workspace.id}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
this.props.router
|
||||
.replace({
|
||||
pathname: '/workspace/[workspaceId]/[pageId]',
|
||||
query: {
|
||||
workspaceId: error.workspace.id,
|
||||
pageId: error.workspace.meta.pageMetas[0].id,
|
||||
},
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({ error: null });
|
||||
});
|
||||
}}
|
||||
>
|
||||
{' '}
|
||||
refresh{' '}
|
||||
</button>
|
||||
</>
|
||||
</>
|
||||
);
|
||||
@ -124,7 +103,7 @@ export class AffineErrorBoundary extends Component<
|
||||
<>
|
||||
{errorDetail}
|
||||
<Provider key="JotaiProvider" store={rootStore}>
|
||||
<DumpInfo router={this.props.router} />
|
||||
<DumpInfo />
|
||||
</Provider>
|
||||
</>
|
||||
);
|