mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
refactor: webpack config (#11421)
This commit is contained in:
5
tools/@types/build-config/__all.d.ts
vendored
5
tools/@types/build-config/__all.d.ts
vendored
@@ -33,6 +33,11 @@ declare interface BUILD_CONFIG_TYPE {
|
||||
// see: tools/workers
|
||||
imageProxyUrl: string;
|
||||
linkPreviewUrl: string;
|
||||
|
||||
CAPTCHA_SITE_KEY: string;
|
||||
SENTRY_DSN: string;
|
||||
MIXPANEL_TOKEN: string;
|
||||
DEBUG_JOTAI: string;
|
||||
}
|
||||
|
||||
declare var BUILD_CONFIG: BUILD_CONFIG_TYPE;
|
||||
|
||||
1
tools/@types/env/__all.d.ts
vendored
1
tools/@types/env/__all.d.ts
vendored
@@ -37,6 +37,7 @@ declare type Environment = {
|
||||
|
||||
// runtime configs
|
||||
publicPath: string;
|
||||
workerPath: string
|
||||
};
|
||||
|
||||
var process: {
|
||||
|
||||
@@ -1,75 +1,130 @@
|
||||
import type { Package } from '@affine-tools/utils/workspace';
|
||||
import webpack, { type Compiler, type Configuration } from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
import { merge } from 'webpack-merge';
|
||||
import { rmSync } from 'node:fs';
|
||||
import { cpus } from 'node:os';
|
||||
|
||||
import { Logger } from '@affine-tools/utils/logger';
|
||||
import { Package } from '@affine-tools/utils/workspace';
|
||||
import { merge } from 'lodash-es';
|
||||
import webpack from 'webpack';
|
||||
import WebpackDevServer, {
|
||||
type Configuration as DevServerConfiguration,
|
||||
} from 'webpack-dev-server';
|
||||
|
||||
import { Option, PackageCommand } from './command';
|
||||
import { createWebpackConfig } from './webpack';
|
||||
import { createHTMLTargetConfig, createWorkerTargetConfig } 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}]`
|
||||
function getBundleConfigs(pkg: Package) {
|
||||
const core = new Package('@affine/core');
|
||||
|
||||
const workerConfigs = [
|
||||
createWorkerTargetConfig(
|
||||
pkg,
|
||||
core.srcPath.join(
|
||||
'modules/workspace-engine/impls/workspace-profile.worker.ts'
|
||||
).value
|
||||
),
|
||||
createWorkerTargetConfig(
|
||||
pkg,
|
||||
core.srcPath.join('modules/pdf/renderer/pdf.worker.ts').value
|
||||
),
|
||||
createWorkerTargetConfig(
|
||||
pkg,
|
||||
core.srcPath.join('blocksuite/extensions/turbo-painter.worker.ts').value
|
||||
),
|
||||
];
|
||||
|
||||
switch (pkg.name) {
|
||||
case '@affine/admin': {
|
||||
return [createHTMLTargetConfig(pkg, pkg.srcPath.join('index.tsx').value)];
|
||||
}
|
||||
case '@affine/web':
|
||||
case '@affine/mobile':
|
||||
case '@affine/ios':
|
||||
case '@affine/android': {
|
||||
workerConfigs.push(
|
||||
createWorkerTargetConfig(
|
||||
pkg,
|
||||
pkg.srcPath.join('nbstore.worker.ts').value
|
||||
)
|
||||
);
|
||||
|
||||
return [
|
||||
createHTMLTargetConfig(
|
||||
pkg,
|
||||
pkg.srcPath.join('index.tsx').value,
|
||||
{},
|
||||
workerConfigs.map(config => config.name)
|
||||
),
|
||||
...workerConfigs,
|
||||
];
|
||||
}
|
||||
case '@affine/electron-renderer': {
|
||||
return [
|
||||
createHTMLTargetConfig(
|
||||
pkg,
|
||||
{
|
||||
index: pkg.srcPath.join('app/index.tsx').value,
|
||||
shell: pkg.srcPath.join('shell/index.tsx').value,
|
||||
popup: pkg.srcPath.join('popup/index.tsx').value,
|
||||
backgroundWorker: pkg.srcPath.join('background-worker/index.ts')
|
||||
.value,
|
||||
},
|
||||
{
|
||||
additionalEntryForSelfhost: false,
|
||||
injectGlobalErrorHandler: false,
|
||||
emitAssetsManifest: false,
|
||||
},
|
||||
workerConfigs.map(config => config.name)
|
||||
),
|
||||
...workerConfigs,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported package: ${pkg.name}`);
|
||||
}
|
||||
const IN_CI = !!process.env.CI;
|
||||
const httpProxyMiddlewareLogLevel = IN_CI ? 'silent' : 'error';
|
||||
|
||||
export async function getConfig(pkg: Package, dev: boolean) {
|
||||
let config = createWebpackConfig(pkg, {
|
||||
mode: dev ? 'development' : 'production',
|
||||
channel: getChannel(),
|
||||
});
|
||||
|
||||
let configOverride: Configuration | undefined;
|
||||
const overrideConfigPath = pkg.join('webpack.config.ts');
|
||||
|
||||
if (overrideConfigPath.isFile()) {
|
||||
const override = await import(overrideConfigPath.toFileUrl().toString());
|
||||
configOverride = override.config ?? override.default;
|
||||
}
|
||||
|
||||
if (configOverride) {
|
||||
config = merge(config, configOverride);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
export async function start(
|
||||
compiler: Compiler,
|
||||
config: Configuration['devServer']
|
||||
): Promise<WebpackDevServer> {
|
||||
const devServer = new WebpackDevServer(config, compiler);
|
||||
|
||||
await devServer.start();
|
||||
|
||||
return devServer;
|
||||
}
|
||||
|
||||
export async function 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'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const defaultDevServerConfig = {
|
||||
host: '0.0.0.0',
|
||||
allowedHosts: 'all',
|
||||
hot: false,
|
||||
liveReload: true,
|
||||
client: {
|
||||
overlay: process.env.DISABLE_DEV_OVERLAY === 'true' ? false : undefined,
|
||||
logging: process.env.CI ? 'none' : 'error',
|
||||
},
|
||||
historyApiFallback: {
|
||||
rewrites: [
|
||||
{
|
||||
from: /.*/,
|
||||
to: () => {
|
||||
return process.env.SELF_HOSTED === 'true'
|
||||
? '/selfhost.html'
|
||||
: '/index.html';
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
proxy: [
|
||||
{
|
||||
context: '/api',
|
||||
target: 'http://localhost:3010',
|
||||
logLevel: httpProxyMiddlewareLogLevel,
|
||||
},
|
||||
{
|
||||
context: '/socket.io',
|
||||
target: 'http://localhost:3010',
|
||||
ws: true,
|
||||
logLevel: httpProxyMiddlewareLogLevel,
|
||||
},
|
||||
{
|
||||
context: '/graphql',
|
||||
target: 'http://localhost:3010',
|
||||
logLevel: httpProxyMiddlewareLogLevel,
|
||||
},
|
||||
],
|
||||
} as DevServerConfiguration;
|
||||
|
||||
export class BundleCommand extends PackageCommand {
|
||||
static override paths = [['bundle'], ['webpack'], ['pack'], ['bun']];
|
||||
@@ -83,19 +138,60 @@ export class BundleCommand extends PackageCommand {
|
||||
});
|
||||
|
||||
async execute() {
|
||||
this.logger.info(`Packing package ${this.package}...`);
|
||||
const pkg = this.workspace.getPackage(this.package);
|
||||
|
||||
const config = await getConfig(
|
||||
this.workspace.getPackage(this.package),
|
||||
this.dev
|
||||
);
|
||||
if (this.dev) {
|
||||
await BundleCommand.dev(pkg);
|
||||
} else {
|
||||
await BundleCommand.build(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
static async build(pkg: Package) {
|
||||
process.env.NODE_ENV = 'production';
|
||||
const logger = new Logger('bundle');
|
||||
logger.info(`Packing package ${pkg.name}...`);
|
||||
logger.info('Cleaning old output...');
|
||||
rmSync(pkg.distPath.value, { recursive: true, force: true });
|
||||
|
||||
const config = getBundleConfigs(pkg);
|
||||
// @ts-expect-error allow
|
||||
config.parallelism = cpus().length;
|
||||
|
||||
const compiler = webpack(config);
|
||||
|
||||
if (this.dev) {
|
||||
await start(compiler, config.devServer);
|
||||
} else {
|
||||
await build(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'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static async dev(pkg: Package, devServerConfig?: DevServerConfiguration) {
|
||||
process.env.NODE_ENV = 'development';
|
||||
const logger = new Logger('bundle');
|
||||
logger.info(`Starting dev server for ${pkg.name}...`);
|
||||
|
||||
const config = getBundleConfigs(pkg);
|
||||
// @ts-expect-error allow
|
||||
config.parallelism = cpus().length;
|
||||
|
||||
const compiler = webpack(config);
|
||||
|
||||
const devServer = new WebpackDevServer(
|
||||
merge({}, defaultDevServerConfig, devServerConfig),
|
||||
compiler
|
||||
);
|
||||
|
||||
await devServer.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,19 +8,14 @@ import { once } from 'lodash-es';
|
||||
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
|
||||
) => {
|
||||
export const getPublicPath = (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.debug ||
|
||||
BUILD_CONFIG.distribution === 'desktop' ||
|
||||
BUILD_CONFIG.distribution === 'ios' ||
|
||||
BUILD_CONFIG.distribution === 'android'
|
||||
@@ -58,11 +53,15 @@ const gitShortHash = once(() => {
|
||||
|
||||
const currentDir = Path.dir(import.meta.url);
|
||||
|
||||
function getHTMLPluginOptions(
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
) {
|
||||
const publicPath = getPublicPath(flags, BUILD_CONFIG);
|
||||
export interface CreateHTMLPluginConfig {
|
||||
filename?: string;
|
||||
additionalEntryForSelfhost?: boolean;
|
||||
injectGlobalErrorHandler?: boolean;
|
||||
emitAssetsManifest?: boolean;
|
||||
}
|
||||
|
||||
function getHTMLPluginOptions(BUILD_CONFIG: BUILD_CONFIG_TYPE) {
|
||||
const publicPath = getPublicPath(BUILD_CONFIG);
|
||||
const cdnOrigin = publicPath.startsWith('/')
|
||||
? undefined
|
||||
: new URL(publicPath).origin;
|
||||
@@ -79,144 +78,159 @@ function getHTMLPluginOptions(
|
||||
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 createBackgroundWorkerHTMLPlugin(
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
) {
|
||||
const htmlPluginOptions = getHTMLPluginOptions(flags, BUILD_CONFIG);
|
||||
|
||||
return new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
chunks: ['backgroundWorker'],
|
||||
filename: `background-worker.html`,
|
||||
});
|
||||
}
|
||||
|
||||
export function createPopupHTMLPlugin(
|
||||
flags: BuildFlags,
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE
|
||||
) {
|
||||
const htmlPluginOptions = getHTMLPluginOptions(flags, BUILD_CONFIG);
|
||||
|
||||
return new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
chunks: ['popup'],
|
||||
filename: `popup.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
|
||||
)
|
||||
const AssetsManifestPlugin = {
|
||||
apply(compiler: Compiler) {
|
||||
compiler.hooks.compilation.tap('assets-manifest-plugin', compilation => {
|
||||
HTMLPlugin.getHooks(compilation).beforeAssetTagGeneration.tap(
|
||||
'assets-manifest-plugin',
|
||||
arg => {
|
||||
if (!compilation.getAsset('assets-manifest.json')) {
|
||||
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)
|
||||
),
|
||||
{
|
||||
immutable: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return arg;
|
||||
css: arg.assets.css.map(file =>
|
||||
file.substring(arg.assets.publicPath.length)
|
||||
),
|
||||
gitHash: gitShortHash(),
|
||||
description: DESCRIPTION,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
),
|
||||
{
|
||||
immutable: false,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const GlobalErrorHandlerPlugin = {
|
||||
apply(compiler: Compiler) {
|
||||
const globalErrorHandler = [
|
||||
'js/global-error-handler.js',
|
||||
readFileSync(currentDir.join('./error-handler.js').toString(), 'utf-8'),
|
||||
];
|
||||
|
||||
compiler.hooks.compilation.tap(
|
||||
'global-error-handler-plugin',
|
||||
compilation => {
|
||||
HTMLPlugin.getHooks(compilation).beforeAssetTagGeneration.tap(
|
||||
'global-error-handler-plugin',
|
||||
arg => {
|
||||
if (!compilation.getAsset(globalErrorHandler[0])) {
|
||||
compilation.emitAsset(
|
||||
globalErrorHandler[0],
|
||||
new webpack.sources.RawSource(globalErrorHandler[1])
|
||||
);
|
||||
arg.assets.js.unshift(
|
||||
arg.assets.publicPath + globalErrorHandler[0]
|
||||
);
|
||||
}
|
||||
|
||||
return arg;
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export function createHTMLPlugins(
|
||||
BUILD_CONFIG: BUILD_CONFIG_TYPE,
|
||||
config: CreateHTMLPluginConfig
|
||||
): WebpackPluginInstance[] {
|
||||
const publicPath = getPublicPath(BUILD_CONFIG);
|
||||
const htmlPluginOptions = getHTMLPluginOptions(BUILD_CONFIG);
|
||||
|
||||
const plugins: WebpackPluginInstance[] = [];
|
||||
plugins.push(
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
chunks: ['index'],
|
||||
filename: config.filename,
|
||||
publicPath,
|
||||
meta: {
|
||||
'env:publicPath': publicPath,
|
||||
},
|
||||
}),
|
||||
// selfhost html
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
meta: {
|
||||
'env:isSelfHosted': 'true',
|
||||
'env:publicPath': '/',
|
||||
},
|
||||
filename: 'selfhost.html',
|
||||
templateParameters: {
|
||||
...htmlPluginOptions.templateParameters,
|
||||
PRECONNECT: '',
|
||||
},
|
||||
}),
|
||||
];
|
||||
})
|
||||
);
|
||||
|
||||
if (BUILD_CONFIG.isElectron) {
|
||||
plugins.push(
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
chunks: ['shell'],
|
||||
filename: 'shell.html',
|
||||
publicPath,
|
||||
meta: {
|
||||
'env:publicPath': publicPath,
|
||||
},
|
||||
}),
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
filename: 'popup.html',
|
||||
chunks: ['popup'],
|
||||
publicPath,
|
||||
meta: {
|
||||
'env:publicPath': publicPath,
|
||||
},
|
||||
}),
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
filename: 'background-worker.html',
|
||||
chunks: ['backgroundWorker'],
|
||||
publicPath,
|
||||
meta: {
|
||||
'env:publicPath': publicPath,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (config.emitAssetsManifest) {
|
||||
plugins.push(AssetsManifestPlugin);
|
||||
}
|
||||
|
||||
if (config.injectGlobalErrorHandler) {
|
||||
plugins.push(GlobalErrorHandlerPlugin);
|
||||
}
|
||||
|
||||
if (config.additionalEntryForSelfhost) {
|
||||
plugins.push(
|
||||
new HTMLPlugin({
|
||||
...htmlPluginOptions,
|
||||
chunks: ['index'],
|
||||
meta: {
|
||||
'env:isSelfHosted': 'true',
|
||||
'env:publicPath': '/',
|
||||
},
|
||||
filename: 'selfhost.html',
|
||||
templateParameters: {
|
||||
...htmlPluginOptions.templateParameters,
|
||||
PRECONNECT: '',
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
@@ -1,127 +1,99 @@
|
||||
import { createRequire } from 'node:module';
|
||||
import path from 'node:path';
|
||||
|
||||
import { getBuildConfig } from '@affine-tools/utils/build-config';
|
||||
import { ProjectRoot } from '@affine-tools/utils/path';
|
||||
import type { Package } from '@affine-tools/utils/workspace';
|
||||
import { Package } from '@affine-tools/utils/workspace';
|
||||
import { PerfseePlugin } from '@perfsee/webpack';
|
||||
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, merge } from 'lodash-es';
|
||||
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 { productionCacheGroups } from './cache-group.js';
|
||||
import {
|
||||
createBackgroundWorkerHTMLPlugin,
|
||||
type CreateHTMLPluginConfig,
|
||||
createHTMLPlugins,
|
||||
createPopupHTMLPlugin,
|
||||
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;
|
||||
|
||||
const OptimizeOptionOptions: (
|
||||
flags: BuildFlags
|
||||
) => webpack.Configuration['optimization'] = flags => ({
|
||||
minimize: flags.mode === 'production',
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: TerserPlugin.swcMinify,
|
||||
exclude: [/plugins\/.+\/.+\.js$/, /plugins\/.+\/.+\.mjs$/],
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
terserOptions: {
|
||||
ecma: 2020,
|
||||
compress: {
|
||||
unused: true,
|
||||
},
|
||||
mangle: {
|
||||
keep_classnames: 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: productionCacheGroups,
|
||||
},
|
||||
});
|
||||
const availableChannels = ['canary', 'beta', 'stable', 'internal'];
|
||||
function getBuildConfigFromEnv(pkg: Package) {
|
||||
const channel = process.env.BUILD_TYPE ?? 'canary';
|
||||
const dev = process.env.NODE_ENV === 'development';
|
||||
if (!availableChannels.includes(channel)) {
|
||||
throw new Error(
|
||||
`BUILD_TYPE must be one of ${availableChannels.join(', ')}, received [${channel}]`
|
||||
);
|
||||
}
|
||||
|
||||
export function createWebpackConfig(
|
||||
return getBuildConfig(pkg, {
|
||||
// @ts-expect-error checked
|
||||
channel,
|
||||
mode: dev ? 'development' : 'production',
|
||||
});
|
||||
}
|
||||
|
||||
export function createHTMLTargetConfig(
|
||||
pkg: Package,
|
||||
flags: BuildFlags
|
||||
entry: string | Record<string, string>,
|
||||
htmlConfig: Partial<CreateHTMLPluginConfig> = {},
|
||||
deps?: string[]
|
||||
): webpack.Configuration {
|
||||
const buildConfig = getBuildConfig(pkg, flags);
|
||||
const httpProxyMiddlewareLogLevel = process.env.CI ? 'silent' : 'error';
|
||||
entry = typeof entry === 'string' ? { index: entry } : entry;
|
||||
|
||||
const config = {
|
||||
name: 'affine',
|
||||
htmlConfig = merge(
|
||||
{},
|
||||
{
|
||||
filename: 'index.html',
|
||||
additionalEntryForSelfhost: true,
|
||||
injectGlobalErrorHandler: true,
|
||||
emitAssetsManifest: true,
|
||||
},
|
||||
htmlConfig
|
||||
);
|
||||
|
||||
const buildConfig = getBuildConfigFromEnv(pkg);
|
||||
|
||||
const config: webpack.Configuration = {
|
||||
//#region basic webpack config
|
||||
name: entry['index'],
|
||||
dependencies: deps,
|
||||
context: pkg.path.value,
|
||||
experiments: {
|
||||
topLevelAwait: true,
|
||||
outputModule: false,
|
||||
syncWebAssembly: true,
|
||||
},
|
||||
entry: {
|
||||
app: pkg.entry ?? './src/index.tsx',
|
||||
},
|
||||
entry,
|
||||
output: {
|
||||
environment: {
|
||||
module: true,
|
||||
dynamicImport: true,
|
||||
},
|
||||
filename:
|
||||
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'
|
||||
: flags.mode === 'production'
|
||||
? 'js/chunk.[name].[contenthash:8].js'
|
||||
: 'js/chunk.[name].js',
|
||||
assetModuleFilename:
|
||||
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',
|
||||
filename: buildConfig.debug
|
||||
? 'js/[name].js'
|
||||
: 'js/[name].[contenthash:8].js',
|
||||
assetModuleFilename: buildConfig.debug
|
||||
? '[name].[contenthash:8][ext]'
|
||||
: 'assets/[name].[contenthash:8][ext][query]',
|
||||
path: pkg.distPath.value,
|
||||
clean: flags.mode === 'production',
|
||||
clean: false,
|
||||
globalObject: 'globalThis',
|
||||
// NOTE(@forehalo): always keep it '/'
|
||||
publicPath: '/',
|
||||
workerPublicPath: '/',
|
||||
},
|
||||
target: ['web', 'es2022'],
|
||||
|
||||
mode: flags.mode,
|
||||
|
||||
devtool:
|
||||
flags.mode === 'production' ? 'source-map' : 'cheap-module-source-map',
|
||||
|
||||
mode: buildConfig.debug ? 'development' : 'production',
|
||||
devtool: buildConfig.debug ? 'cheap-module-source-map' : 'source-map',
|
||||
resolve: {
|
||||
symlinks: true,
|
||||
extensionAlias: {
|
||||
@@ -139,7 +111,9 @@ export function createWebpackConfig(
|
||||
).value,
|
||||
},
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region module config
|
||||
module: {
|
||||
parser: {
|
||||
javascript: {
|
||||
@@ -151,6 +125,7 @@ export function createWebpackConfig(
|
||||
strictExportPresence: true,
|
||||
},
|
||||
},
|
||||
//#region rules
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js?$/,
|
||||
@@ -240,7 +215,7 @@ export function createWebpackConfig(
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
flags.mode === 'development'
|
||||
buildConfig.debug
|
||||
? 'style-loader'
|
||||
: MiniCssExtractPlugin.loader,
|
||||
{
|
||||
@@ -283,28 +258,16 @@ export function createWebpackConfig(
|
||||
],
|
||||
},
|
||||
],
|
||||
//#endregion
|
||||
},
|
||||
//#endregion
|
||||
|
||||
//#region plugins
|
||||
plugins: compact([
|
||||
IN_CI ? null : new webpack.ProgressPlugin({ percentBy: 'entries' }),
|
||||
flags.mode === 'development'
|
||||
? null
|
||||
: // todo: support multiple entry points
|
||||
new MiniCssExtractPlugin({
|
||||
filename: `[name].[contenthash:8].css`,
|
||||
ignoreOrder: true,
|
||||
}),
|
||||
new VanillaExtractPlugin(),
|
||||
!IN_CI && new webpack.ProgressPlugin({ percentBy: 'entries' }),
|
||||
...createHTMLPlugins(buildConfig, htmlConfig),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(flags.mode),
|
||||
'process.env.CAPTCHA_SITE_KEY': JSON.stringify(
|
||||
process.env.CAPTCHA_SITE_KEY
|
||||
),
|
||||
'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN),
|
||||
'process.env.BUILD_TYPE': JSON.stringify(process.env.BUILD_TYPE),
|
||||
'process.env.MIXPANEL_TOKEN': JSON.stringify(
|
||||
process.env.MIXPANEL_TOKEN
|
||||
),
|
||||
'process.env.DEBUG_JOTAI': JSON.stringify(process.env.DEBUG_JOTAI),
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
...Object.entries(buildConfig).reduce(
|
||||
(def, [k, v]) => {
|
||||
def[`BUILD_CONFIG.${k}`] = JSON.stringify(v);
|
||||
@@ -313,90 +276,100 @@ export function createWebpackConfig(
|
||||
{} as Record<string, string>
|
||||
),
|
||||
}),
|
||||
buildConfig.isAdmin && flags.mode !== 'production'
|
||||
? null
|
||||
: new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
// copy the shared public assets into dist
|
||||
from: pkg.workspace.getPackage('@affine/core').join('public')
|
||||
.value,
|
||||
},
|
||||
],
|
||||
}),
|
||||
flags.mode === 'production' &&
|
||||
(buildConfig.isWeb || buildConfig.isMobileWeb || buildConfig.isAdmin) &&
|
||||
process.env.R2_SECRET_ACCESS_KEY
|
||||
? new WebpackS3Plugin()
|
||||
: null,
|
||||
!buildConfig.debug &&
|
||||
// todo: support multiple entry points
|
||||
new MiniCssExtractPlugin({
|
||||
filename: `[name].[contenthash:8].css`,
|
||||
ignoreOrder: true,
|
||||
}),
|
||||
new VanillaExtractPlugin(),
|
||||
!buildConfig.isAdmin &&
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{
|
||||
// copy the shared public assets into dist
|
||||
from: new Package('@affine/core').join('public').value,
|
||||
},
|
||||
],
|
||||
}),
|
||||
!buildConfig.debug &&
|
||||
(buildConfig.isWeb || buildConfig.isMobileWeb || buildConfig.isAdmin) &&
|
||||
process.env.R2_SECRET_ACCESS_KEY &&
|
||||
new WebpackS3Plugin(),
|
||||
!buildConfig.debug &&
|
||||
process.env.PERFSEE_TOKEN &&
|
||||
new PerfseePlugin({
|
||||
project: 'affine-toeverything',
|
||||
}),
|
||||
process.env.SENTRY_AUTH_TOKEN &&
|
||||
process.env.SENTRY_ORG &&
|
||||
process.env.SENTRY_PROJECT &&
|
||||
sentryWebpackPlugin({
|
||||
org: process.env.SENTRY_ORG,
|
||||
project: process.env.SENTRY_PROJECT,
|
||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
}),
|
||||
// sourcemap url like # sourceMappingURL=76-6370cd185962bc89.js.map wont load in electron
|
||||
// this is because the default file:// protocol will be ignored by Chromium
|
||||
// so we need to replace the sourceMappingURL to assets:// protocol
|
||||
// for example:
|
||||
// replace # sourceMappingURL=76-6370cd185962bc89.js.map
|
||||
// to # sourceMappingURL=assets://./{dir}/76-6370cd185962bc89.js.map
|
||||
buildConfig.isElectron &&
|
||||
new webpack.SourceMapDevToolPlugin({
|
||||
append: pathData => {
|
||||
return `\n//# sourceMappingURL=assets://./${pathData.filename}.map`;
|
||||
},
|
||||
filename: '[file].map',
|
||||
}),
|
||||
]),
|
||||
//#endregion
|
||||
|
||||
stats: {
|
||||
errorDetails: true,
|
||||
},
|
||||
optimization: OptimizeOptionOptions(flags),
|
||||
devServer: {
|
||||
host: '0.0.0.0',
|
||||
allowedHosts: 'all',
|
||||
hot: false,
|
||||
liveReload: true,
|
||||
client: {
|
||||
overlay: process.env.DISABLE_DEV_OVERLAY === 'true' ? false : undefined,
|
||||
logging: process.env.CI ? 'none' : 'error',
|
||||
},
|
||||
historyApiFallback: {
|
||||
rewrites: [
|
||||
{
|
||||
from: /.*/,
|
||||
to: () => {
|
||||
return process.env.SELF_HOSTED === 'true'
|
||||
? '/selfhost.html'
|
||||
: '/index.html';
|
||||
|
||||
//#region optimization
|
||||
optimization: {
|
||||
minimize: !buildConfig.debug,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: TerserPlugin.swcMinify,
|
||||
exclude: [/plugins\/.+\/.+\.js$/, /plugins\/.+\/.+\.mjs$/],
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
terserOptions: {
|
||||
ecma: 2020,
|
||||
compress: {
|
||||
unused: true,
|
||||
},
|
||||
mangle: {
|
||||
keep_classnames: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
removeEmptyChunks: true,
|
||||
providedExports: true,
|
||||
usedExports: true,
|
||||
sideEffects: true,
|
||||
removeAvailableModules: true,
|
||||
runtimeChunk: {
|
||||
name: 'runtime',
|
||||
},
|
||||
static: [
|
||||
{
|
||||
directory: pkg.workspace.getPackage('@affine/core').join('public')
|
||||
.value,
|
||||
publicPath: '/',
|
||||
watch: !IN_CI,
|
||||
staticOptions: {
|
||||
immutable: IN_CI,
|
||||
maxAge: '1d',
|
||||
},
|
||||
},
|
||||
],
|
||||
proxy: [
|
||||
{
|
||||
context: '/api',
|
||||
target: 'http://localhost:3010',
|
||||
logLevel: httpProxyMiddlewareLogLevel,
|
||||
},
|
||||
{
|
||||
context: '/socket.io',
|
||||
target: 'http://localhost:3010',
|
||||
ws: true,
|
||||
logLevel: httpProxyMiddlewareLogLevel,
|
||||
},
|
||||
{
|
||||
context: '/graphql',
|
||||
target: 'http://localhost:3010',
|
||||
logLevel: httpProxyMiddlewareLogLevel,
|
||||
},
|
||||
],
|
||||
} as DevServerConfiguration,
|
||||
} satisfies webpack.Configuration;
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
minSize: 1,
|
||||
minChunks: 1,
|
||||
maxInitialRequests: Number.MAX_SAFE_INTEGER,
|
||||
maxAsyncRequests: Number.MAX_SAFE_INTEGER,
|
||||
cacheGroups: productionCacheGroups,
|
||||
},
|
||||
},
|
||||
//#endregion
|
||||
};
|
||||
|
||||
if (flags.mode === 'production' && process.env.PERFSEE_TOKEN) {
|
||||
config.plugins.push(
|
||||
new PerfseePlugin({
|
||||
project: 'affine-toeverything',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (flags.mode === 'development' && !IN_CI) {
|
||||
if (buildConfig.debug && !IN_CI) {
|
||||
config.optimization = {
|
||||
...config.optimization,
|
||||
minimize: false,
|
||||
@@ -426,42 +399,186 @@ export function createWebpackConfig(
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
config.plugins = config.plugins.concat(createHTMLPlugins(flags, buildConfig));
|
||||
|
||||
if (buildConfig.isElectron) {
|
||||
config.plugins.push(createShellHTMLPlugin(flags, buildConfig));
|
||||
config.plugins.push(createBackgroundWorkerHTMLPlugin(flags, buildConfig));
|
||||
config.plugins.push(createPopupHTMLPlugin(flags, buildConfig));
|
||||
|
||||
// sourcemap url like # sourceMappingURL=76-6370cd185962bc89.js.map wont load in electron
|
||||
// this is because the default file:// protocol will be ignored by Chromium
|
||||
// so we need to replace the sourceMappingURL to assets:// protocol
|
||||
// for example:
|
||||
// replace # sourceMappingURL=76-6370cd185962bc89.js.map
|
||||
// to # sourceMappingURL=assets://./{dir}/76-6370cd185962bc89.js.map
|
||||
config.plugins.push(
|
||||
new webpack.SourceMapDevToolPlugin({
|
||||
append: pathData => {
|
||||
return `\n//# sourceMappingURL=assets://./${pathData.filename}.map`;
|
||||
},
|
||||
filename: '[file].map',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
export function createWorkerTargetConfig(
|
||||
pkg: Package,
|
||||
entry: string
|
||||
): Omit<webpack.Configuration, 'name'> & { name: string } {
|
||||
const workerName = path.basename(entry).replace(/\.([^.]+)$/, '');
|
||||
if (!workerName.endsWith('.worker')) {
|
||||
throw new Error('Worker name must end with `.worker.[ext]`');
|
||||
}
|
||||
const buildConfig = getBuildConfigFromEnv(pkg);
|
||||
|
||||
return {
|
||||
name: entry,
|
||||
context: pkg.path.value,
|
||||
experiments: {
|
||||
topLevelAwait: true,
|
||||
outputModule: false,
|
||||
syncWebAssembly: true,
|
||||
},
|
||||
entry: {
|
||||
[workerName]: entry,
|
||||
},
|
||||
output: {
|
||||
filename: 'js/[name].js',
|
||||
path: pkg.distPath.value,
|
||||
clean: false,
|
||||
globalObject: 'globalThis',
|
||||
// NOTE(@forehalo): always keep it '/'
|
||||
publicPath: '/',
|
||||
},
|
||||
target: ['webworker', 'es2022'],
|
||||
mode: buildConfig.debug ? 'development' : 'production',
|
||||
devtool: buildConfig.debug ? 'cheap-module-source-map' : 'source-map',
|
||||
resolve: {
|
||||
symlinks: true,
|
||||
extensionAlias: {
|
||||
'.js': ['.js', '.ts'],
|
||||
'.mjs': ['.mjs', '.mts'],
|
||||
},
|
||||
extensions: ['.js', '.ts'],
|
||||
alias: {
|
||||
yjs: ProjectRoot.join('node_modules', 'yjs').value,
|
||||
},
|
||||
},
|
||||
|
||||
module: {
|
||||
parser: {
|
||||
javascript: {
|
||||
// Do not mock Node.js globals
|
||||
node: false,
|
||||
requireJs: false,
|
||||
import: true,
|
||||
// Treat as missing export as error
|
||||
strictExportPresence: true,
|
||||
},
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js?$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
enforce: 'pre',
|
||||
include: /@blocksuite/,
|
||||
use: ['source-map-loader'],
|
||||
},
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'swc-loader',
|
||||
options: {
|
||||
// https://swc.rs/docs/configuring-swc/
|
||||
jsc: {
|
||||
preserveAllComments: true,
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
dynamicImport: true,
|
||||
topLevelAwait: false,
|
||||
tsx: false,
|
||||
decorators: true,
|
||||
},
|
||||
target: 'es2022',
|
||||
externalHelpers: false,
|
||||
transform: {
|
||||
useDefineForClassFields: false,
|
||||
decoratorVersion: '2022-03',
|
||||
},
|
||||
},
|
||||
sourceMaps: true,
|
||||
inlineSourcesContent: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.tsx$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'swc-loader',
|
||||
options: {
|
||||
// https://swc.rs/docs/configuring-swc/
|
||||
jsc: {
|
||||
preserveAllComments: true,
|
||||
parser: {
|
||||
syntax: 'typescript',
|
||||
dynamicImport: true,
|
||||
topLevelAwait: false,
|
||||
tsx: true,
|
||||
decorators: true,
|
||||
},
|
||||
target: 'es2022',
|
||||
externalHelpers: false,
|
||||
transform: {
|
||||
react: {
|
||||
runtime: 'automatic',
|
||||
},
|
||||
useDefineForClassFields: false,
|
||||
decoratorVersion: '2022-03',
|
||||
},
|
||||
},
|
||||
sourceMaps: true,
|
||||
inlineSourcesContent: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: compact([
|
||||
new webpack.DefinePlugin(
|
||||
Object.entries(buildConfig).reduce(
|
||||
(def, [k, v]) => {
|
||||
def[`BUILD_CONFIG.${k}`] = JSON.stringify(v);
|
||||
return def;
|
||||
},
|
||||
{} as Record<string, string>
|
||||
)
|
||||
),
|
||||
process.env.SENTRY_AUTH_TOKEN &&
|
||||
process.env.SENTRY_ORG &&
|
||||
process.env.SENTRY_PROJECT &&
|
||||
sentryWebpackPlugin({
|
||||
org: process.env.SENTRY_ORG,
|
||||
project: process.env.SENTRY_PROJECT,
|
||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||
}),
|
||||
]),
|
||||
stats: {
|
||||
errorDetails: true,
|
||||
},
|
||||
optimization: {
|
||||
minimize: !buildConfig.debug,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: TerserPlugin.swcMinify,
|
||||
exclude: [/plugins\/.+\/.+\.js$/, /plugins\/.+\/.+\.mjs$/],
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
terserOptions: {
|
||||
ecma: 2020,
|
||||
compress: {
|
||||
unused: true,
|
||||
},
|
||||
mangle: {
|
||||
keep_classnames: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
removeEmptyChunks: true,
|
||||
providedExports: true,
|
||||
usedExports: true,
|
||||
sideEffects: true,
|
||||
removeAvailableModules: true,
|
||||
runtimeChunk: false,
|
||||
splitChunks: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ export function getBuildConfig(
|
||||
discordUrl: 'https://affine.pro/redirect/discord',
|
||||
imageProxyUrl: '/api/worker/image-proxy',
|
||||
linkPreviewUrl: '/api/worker/link-preview',
|
||||
CAPTCHA_SITE_KEY: process.env.CAPTCHA_SITE_KEY ?? '',
|
||||
SENTRY_DSN: process.env.SENTRY_DSN ?? '',
|
||||
MIXPANEL_TOKEN: process.env.MIXPANEL_TOKEN ?? '',
|
||||
DEBUG_JOTAI: process.env.DEBUG_JOTAI ?? '',
|
||||
};
|
||||
},
|
||||
get beta() {
|
||||
|
||||
@@ -923,6 +923,7 @@ export const PackageList = [
|
||||
workspaceDependencies: [
|
||||
'packages/frontend/component',
|
||||
'packages/frontend/core',
|
||||
'packages/common/env',
|
||||
'packages/frontend/i18n',
|
||||
'packages/common/nbstore',
|
||||
'blocksuite/affine/all',
|
||||
@@ -961,6 +962,7 @@ export const PackageList = [
|
||||
workspaceDependencies: [
|
||||
'packages/frontend/component',
|
||||
'packages/frontend/core',
|
||||
'packages/common/env',
|
||||
'packages/frontend/i18n',
|
||||
'packages/common/nbstore',
|
||||
'blocksuite/affine/all',
|
||||
@@ -976,6 +978,7 @@ export const PackageList = [
|
||||
workspaceDependencies: [
|
||||
'packages/frontend/component',
|
||||
'packages/frontend/core',
|
||||
'packages/common/env',
|
||||
'packages/frontend/i18n',
|
||||
'packages/common/nbstore',
|
||||
'blocksuite/affine/all',
|
||||
@@ -988,6 +991,7 @@ export const PackageList = [
|
||||
workspaceDependencies: [
|
||||
'packages/frontend/component',
|
||||
'packages/frontend/core',
|
||||
'packages/common/env',
|
||||
'packages/frontend/i18n',
|
||||
'packages/common/nbstore',
|
||||
'packages/frontend/track',
|
||||
|
||||
Reference in New Issue
Block a user