mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
refactor(core): split web entry from core (#6082)
This pr is trying to split `web` and `electron` entries from `core`. It allows more platform-related optimization to be addressed in each entry. We should remove all browser/electron only codes from `core` eventually, this is the very first step for that.
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const child = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
'--loader',
|
||||
'ts-node/esm/transpile-only',
|
||||
fileURLToPath(new URL('./build-core.ts', import.meta.url)),
|
||||
...process.argv.slice(2),
|
||||
],
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
if (child.status) process.exit(child.status);
|
||||
@@ -1,11 +1,13 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
|
||||
import webpack from 'webpack';
|
||||
|
||||
import type { BuildFlags } from '../config/index.js';
|
||||
import { projectRoot } from '../config/index.js';
|
||||
import { buildI18N } from '../util/i18n.js';
|
||||
import { createWebpackConfig } from '../webpack/webpack.config.js';
|
||||
|
||||
const cwd = path.resolve(projectRoot, 'packages/frontend/core');
|
||||
let cwd: string;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const buildType = process.env.BUILD_TYPE_OVERRIDE || process.env.BUILD_TYPE;
|
||||
@@ -31,15 +33,20 @@ const getChannel = () => {
|
||||
}
|
||||
};
|
||||
|
||||
let entry: string | undefined;
|
||||
|
||||
const { DISTRIBUTION } = process.env;
|
||||
|
||||
const getDistribution = () => {
|
||||
switch (process.env.DISTRIBUTION) {
|
||||
switch (DISTRIBUTION) {
|
||||
case 'browser':
|
||||
case 'desktop':
|
||||
return process.env.DISTRIBUTION;
|
||||
case undefined: {
|
||||
console.log('DISTRIBUTION is not set, defaulting to browser');
|
||||
case undefined:
|
||||
cwd = path.join(projectRoot, 'packages/frontend/web');
|
||||
return 'browser';
|
||||
}
|
||||
case 'desktop':
|
||||
cwd = path.join(projectRoot, 'packages/frontend/electron');
|
||||
entry = path.join(cwd, 'renderer', 'index.tsx');
|
||||
return DISTRIBUTION;
|
||||
default: {
|
||||
throw new Error('DISTRIBUTION must be one of browser, desktop');
|
||||
}
|
||||
@@ -51,24 +58,19 @@ const flags = {
|
||||
mode: 'production',
|
||||
channel: getChannel(),
|
||||
coverage: process.env.COVERAGE === 'true',
|
||||
entry,
|
||||
} satisfies BuildFlags;
|
||||
|
||||
buildI18N();
|
||||
spawn(
|
||||
'node',
|
||||
[
|
||||
'--loader',
|
||||
'ts-node/esm/transpile-only',
|
||||
'../../../node_modules/webpack/bin/webpack.js',
|
||||
'--mode',
|
||||
'production',
|
||||
'--env',
|
||||
'flags=' + Buffer.from(JSON.stringify(flags), 'utf-8').toString('hex'),
|
||||
].filter((v): v is string => !!v),
|
||||
{
|
||||
cwd,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: process.env,
|
||||
|
||||
// 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,16 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const child = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
'--loader',
|
||||
'ts-node/esm/transpile-only',
|
||||
fileURLToPath(new URL('./dev-core.ts', import.meta.url)),
|
||||
...process.argv.slice(2),
|
||||
],
|
||||
{ stdio: 'inherit' }
|
||||
);
|
||||
|
||||
if (child.status) process.exit(child.status);
|
||||
@@ -1,207 +0,0 @@
|
||||
import type { ChildProcess } from 'node:child_process';
|
||||
import { spawn } from 'node:child_process';
|
||||
import { existsSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import * as p from '@clack/prompts';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
import { type BuildFlags, projectRoot } from '../config/index.js';
|
||||
import { watchI18N } from '../util/i18n.js';
|
||||
|
||||
const cwd = path.resolve(projectRoot, 'packages/frontend/core');
|
||||
|
||||
const flags: BuildFlags = {
|
||||
distribution: 'browser',
|
||||
mode: 'development',
|
||||
channel: 'canary',
|
||||
coverage: process.env.COVERAGE === 'true',
|
||||
localBlockSuite: undefined,
|
||||
};
|
||||
|
||||
if (process.argv.includes('--static')) {
|
||||
await awaitChildProcess(
|
||||
spawn(
|
||||
'node',
|
||||
[
|
||||
'--loader',
|
||||
'ts-node/esm/transpile-only',
|
||||
'../../../node_modules/webpack/bin/webpack.js',
|
||||
'serve',
|
||||
'--mode',
|
||||
'development',
|
||||
'--no-client-overlay',
|
||||
'--no-live-reload',
|
||||
'--env',
|
||||
'flags=' + Buffer.from(JSON.stringify(flags), 'utf-8').toString('hex'),
|
||||
].filter((v): v is string => !!v),
|
||||
{
|
||||
cwd,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: process.env,
|
||||
}
|
||||
)
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const files = ['.env', '.env.local'];
|
||||
|
||||
for (const file of files) {
|
||||
if (existsSync(path.resolve(projectRoot, file))) {
|
||||
config({
|
||||
path: path.resolve(projectRoot, file),
|
||||
});
|
||||
console.log(`${file} loaded`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const buildFlags = await p.group(
|
||||
{
|
||||
distribution: () =>
|
||||
p.select({
|
||||
message: 'Distribution',
|
||||
options: [
|
||||
{
|
||||
value: 'browser',
|
||||
},
|
||||
{
|
||||
value: 'desktop',
|
||||
},
|
||||
],
|
||||
initialValue: 'browser',
|
||||
}),
|
||||
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',
|
||||
}),
|
||||
debugBlockSuite: () =>
|
||||
p.confirm({
|
||||
message: 'Debug blocksuite locally?',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('Operation cancelled.');
|
||||
process.exit(0);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (buildFlags.debugBlockSuite) {
|
||||
const { config } = await import('dotenv');
|
||||
const envLocal = config({
|
||||
path: path.resolve(cwd, '.env.local'),
|
||||
});
|
||||
|
||||
const localBlockSuite = await p.text({
|
||||
message: 'local blocksuite PATH',
|
||||
initialValue: envLocal.error
|
||||
? undefined
|
||||
: envLocal.parsed?.LOCAL_BLOCK_SUITE,
|
||||
});
|
||||
if (typeof localBlockSuite !== 'string') {
|
||||
throw new Error('local blocksuite PATH is required');
|
||||
}
|
||||
if (!existsSync(localBlockSuite)) {
|
||||
throw new Error(`local blocksuite not found: ${localBlockSuite}`);
|
||||
}
|
||||
flags.localBlockSuite = localBlockSuite;
|
||||
}
|
||||
|
||||
flags.distribution = buildFlags.distribution as any;
|
||||
flags.mode = buildFlags.mode as any;
|
||||
flags.channel = buildFlags.channel as any;
|
||||
flags.coverage = buildFlags.coverage;
|
||||
|
||||
watchI18N();
|
||||
|
||||
function awaitChildProcess(child: ChildProcess): Promise<number> {
|
||||
return new Promise<number>((resolve, reject) => {
|
||||
const handleExitCode = (code: number | null) => {
|
||||
if (code) {
|
||||
reject(
|
||||
new Error(
|
||||
`Child process at ${
|
||||
(child as any).cwd
|
||||
} fails: ${child.spawnargs.join(' ')}`
|
||||
)
|
||||
);
|
||||
} else {
|
||||
resolve(0);
|
||||
}
|
||||
};
|
||||
|
||||
child.on('error', () => handleExitCode(child.exitCode));
|
||||
child.on('exit', code => handleExitCode(code));
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await awaitChildProcess(
|
||||
spawn('node', ['build-edgeless.mjs'], {
|
||||
cwd: path.resolve(projectRoot, 'packages/frontend/templates'),
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: process.env,
|
||||
})
|
||||
);
|
||||
// Start webpack
|
||||
await awaitChildProcess(
|
||||
spawn(
|
||||
'node',
|
||||
[
|
||||
'--loader',
|
||||
'ts-node/esm/transpile-only',
|
||||
'../../../node_modules/webpack/bin/webpack.js',
|
||||
flags.mode === 'development' ? 'serve' : undefined,
|
||||
'--mode',
|
||||
flags.mode === 'development' ? 'development' : 'production',
|
||||
'--env',
|
||||
'flags=' + Buffer.from(JSON.stringify(flags), 'utf-8').toString('hex'),
|
||||
].filter((v): v is string => !!v),
|
||||
{
|
||||
cwd,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: process.env,
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error during build:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
143
tools/cli/src/bin/dev.ts
Normal file
143
tools/cli/src/bin/dev.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
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 { type BuildFlags, projectRoot } from '../config/index.js';
|
||||
import { watchI18N } from '../util/i18n.js';
|
||||
import { createWebpackConfig } from '../webpack/webpack.config.js';
|
||||
|
||||
const flags: BuildFlags = {
|
||||
distribution: 'browser',
|
||||
mode: 'development',
|
||||
channel: 'canary',
|
||||
coverage: process.env.COVERAGE === 'true',
|
||||
localBlockSuite: undefined,
|
||||
};
|
||||
|
||||
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, debugBlockSuite: false }
|
||||
: ((await p.group(
|
||||
{
|
||||
distribution: () =>
|
||||
p.select({
|
||||
message: 'Distribution',
|
||||
options: [
|
||||
{
|
||||
value: 'browser',
|
||||
},
|
||||
{
|
||||
value: 'desktop',
|
||||
},
|
||||
],
|
||||
initialValue: 'browser',
|
||||
}),
|
||||
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',
|
||||
}),
|
||||
debugBlockSuite: () =>
|
||||
p.confirm({
|
||||
message: 'Debug blocksuite locally?',
|
||||
initialValue: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
p.cancel('Operation cancelled.');
|
||||
process.exit(0);
|
||||
},
|
||||
}
|
||||
)) as BuildFlags & { debugBlockSuite: boolean });
|
||||
|
||||
flags.distribution = buildFlags.distribution;
|
||||
flags.mode = buildFlags.mode;
|
||||
flags.channel = buildFlags.channel;
|
||||
flags.coverage = buildFlags.coverage;
|
||||
|
||||
const cwd =
|
||||
flags.distribution === 'browser'
|
||||
? join(projectRoot, 'packages', 'frontend', 'web')
|
||||
: join(projectRoot, 'packages', 'frontend', 'electron');
|
||||
|
||||
if (buildFlags.debugBlockSuite) {
|
||||
const { config } = await import('dotenv');
|
||||
const envLocal = config({
|
||||
path: join(cwd, '.env.local'),
|
||||
});
|
||||
|
||||
const localBlockSuite = await p.text({
|
||||
message: 'local blocksuite PATH',
|
||||
initialValue: envLocal.error
|
||||
? undefined
|
||||
: envLocal.parsed?.LOCAL_BLOCK_SUITE,
|
||||
});
|
||||
if (typeof localBlockSuite !== 'string') {
|
||||
throw new Error('local blocksuite PATH is required');
|
||||
}
|
||||
if (!existsSync(localBlockSuite)) {
|
||||
throw new Error(`local blocksuite not found: ${localBlockSuite}`);
|
||||
}
|
||||
flags.localBlockSuite = localBlockSuite;
|
||||
}
|
||||
|
||||
watchI18N();
|
||||
|
||||
try {
|
||||
// @ts-expect-error no types
|
||||
await import('@affine/templates/build-edgeless');
|
||||
const config = createWebpackConfig(cwd, flags);
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user