diff --git a/tests/affine-local/dev-server.ts b/tests/affine-local/dev-server.ts new file mode 100644 index 0000000000..cf8a8ff846 --- /dev/null +++ b/tests/affine-local/dev-server.ts @@ -0,0 +1,35 @@ +import { getConfig, start } from '@affine-tools/cli/bundle'; +import { Workspace } from '@affine-tools/utils/workspace'; +import webpack from 'webpack'; + +export default async () => { + const ws = new Workspace(); + const webpackConfig = await getConfig(ws.getPackage('@affine/web'), true); + const definedPort = webpackConfig.devServer?.port ?? 8080; + + await new Promise((resolve, reject) => { + start(webpack(webpackConfig), { + ...webpackConfig.devServer, + onListening: server => { + // dev server has already started + if (server.options.port !== definedPort) { + server.compiler.close(reject); + server.stop().catch(reject); + resolve(); + } + }, + proxy: [], + }) + .then(server => { + server.middleware?.waitUntilValid?.(stats => { + if (stats?.hasErrors()) { + reject(new Error('Webpack build failed')); + } else { + resolve(); + } + }); + }) + .catch(reject); + }); + console.log('Dev server started'); +}; diff --git a/tests/affine-local/package.json b/tests/affine-local/package.json index 19e8a4f5ab..9cc4f59d3a 100644 --- a/tests/affine-local/package.json +++ b/tests/affine-local/package.json @@ -7,7 +7,10 @@ }, "devDependencies": { "@affine-test/kit": "workspace:*", - "@playwright/test": "=1.51.1" + "@affine-tools/cli": "workspace:*", + "@affine-tools/utils": "workspace:*", + "@playwright/test": "=1.51.1", + "webpack": "^5.98.0" }, "version": "0.20.0" } diff --git a/tests/affine-local/playwright.config.ts b/tests/affine-local/playwright.config.ts index 610a857c63..cf86af2383 100644 --- a/tests/affine-local/playwright.config.ts +++ b/tests/affine-local/playwright.config.ts @@ -3,7 +3,6 @@ import type { PlaywrightTestConfig, PlaywrightWorkerOptions, } from '@playwright/test'; -// import { devices } from '@playwright/test'; /** * Read environment variables from file. @@ -19,6 +18,7 @@ const config: PlaywrightTestConfig = { fullyParallel: true, timeout: process.env.CI ? 50_000 : 30_000, outputDir: testResultDir, + globalSetup: './dev-server.ts', use: { baseURL: 'http://localhost:8080/', browserName: @@ -42,19 +42,6 @@ const config: PlaywrightTestConfig = { // default 'list' when running locally // See https://playwright.dev/docs/test-reporters#github-actions-annotations reporter: process.env.CI ? 'github' : 'list', - - webServer: [ - // Intentionally not building the web, reminds you to run it by yourself. - { - command: 'yarn run -T affine dev -p @affine/web', - port: 8080, - timeout: 120 * 1000, - reuseExistingServer: !process.env.CI, - env: { - COVERAGE: process.env.COVERAGE || 'false', - }, - }, - ], }; if (process.env.CI) { diff --git a/tests/affine-local/tsconfig.json b/tests/affine-local/tsconfig.json index 95f29c8eff..3e289affd4 100644 --- a/tests/affine-local/tsconfig.json +++ b/tests/affine-local/tsconfig.json @@ -6,5 +6,9 @@ "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo" }, "include": ["./e2e"], - "references": [{ "path": "../kit" }] + "references": [ + { "path": "../kit" }, + { "path": "../../tools/cli" }, + { "path": "../../tools/utils" } + ] } diff --git a/tools/cli/package.json b/tools/cli/package.json index 449f8109c9..edfa6cd83e 100644 --- a/tools/cli/package.json +++ b/tools/cli/package.json @@ -7,7 +7,8 @@ "r": "./bin/runner.js" }, "exports": { - "./loader": "./loader.js" + "./loader": "./loader.js", + "./bundle": "./src/bundle.ts" }, "scripts": { "affine": "r ./src/affine.ts" diff --git a/tools/cli/src/bundle.ts b/tools/cli/src/bundle.ts index b41cf8b52f..34078d974a 100644 --- a/tools/cli/src/bundle.ts +++ b/tools/cli/src/bundle.ts @@ -1,3 +1,4 @@ +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'; @@ -21,6 +22,55 @@ function getChannel() { } } +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 { + 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')); + } + } + }); +} + export class BundleCommand extends PackageCommand { static override paths = [['bundle'], ['webpack'], ['pack'], ['bun']]; @@ -35,60 +85,17 @@ export class BundleCommand extends PackageCommand { async execute() { this.logger.info(`Packing package ${this.package}...`); - const config = await this.getConfig(); + const config = await getConfig( + this.workspace.getPackage(this.package), + this.dev + ); const compiler = webpack(config); if (this.dev) { - await this.start(compiler, config.devServer); + await start(compiler, config.devServer); } else { - await this.build(compiler); + await build(compiler); } } - - async getConfig() { - let config = createWebpackConfig(this.workspace.getPackage(this.package), { - mode: this.dev ? 'development' : 'production', - channel: getChannel(), - }); - - let configOverride: Configuration | undefined; - const overrideConfigPath = this.workspace - .getPackage(this.package) - .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; - } - - async start(compiler: Compiler, config: Configuration['devServer']) { - const devServer = new WebpackDevServer(config, compiler); - - await devServer.start(); - } - - async 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')); - } - } - }); - } } diff --git a/tools/cli/src/webpack/html-plugin.ts b/tools/cli/src/webpack/html-plugin.ts index 8ac216f852..6b804ee51e 100644 --- a/tools/cli/src/webpack/html-plugin.ts +++ b/tools/cli/src/webpack/html-plugin.ts @@ -4,7 +4,7 @@ import { readFileSync } from 'node:fs'; import { Path, ProjectRoot } from '@affine-tools/utils/path'; import { Repository } from '@napi-rs/simple-git'; import HTMLPlugin from 'html-webpack-plugin'; -import once from 'lodash-es/once'; +import { once } from 'lodash-es'; import type { Compiler, WebpackPluginInstance } from 'webpack'; import webpack from 'webpack'; diff --git a/tools/cli/src/webpack/index.ts b/tools/cli/src/webpack/index.ts index 24fe82e3db..1da245034e 100644 --- a/tools/cli/src/webpack/index.ts +++ b/tools/cli/src/webpack/index.ts @@ -7,7 +7,7 @@ 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/compact'; +import { compact } from 'lodash-es'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import TerserPlugin from 'terser-webpack-plugin'; import webpack from 'webpack'; @@ -227,7 +227,7 @@ export function createWebpackConfig( }, { test: /\.(ttf|eot|woff|woff2)$/, - type: 'asset/resource', + type: IN_CI ? 'asset/inline' : 'asset/resource', }, { test: /\.txt$/, @@ -313,7 +313,7 @@ export function createWebpackConfig( {} as Record ), }), - buildConfig.isAdmin + buildConfig.isAdmin && flags.mode !== 'production' ? null : new CopyPlugin({ patterns: [ @@ -360,7 +360,11 @@ export function createWebpackConfig( directory: pkg.workspace.getPackage('@affine/core').join('public') .value, publicPath: '/', - watch: true, + watch: !IN_CI, + staticOptions: { + immutable: IN_CI, + maxAge: '1d', + }, }, ], proxy: [ diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts index 0fde1809cc..af97671c99 100644 --- a/tools/utils/src/workspace.gen.ts +++ b/tools/utils/src/workspace.gen.ts @@ -1080,7 +1080,7 @@ export const PackageList = [ { location: 'tests/affine-local', name: '@affine-test/affine-local', - workspaceDependencies: ['tests/kit'], + workspaceDependencies: ['tests/kit', 'tools/cli', 'tools/utils'], }, { location: 'tests/affine-mobile', diff --git a/yarn.lock b/yarn.lock index f924530398..e1e8bad4f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -64,7 +64,10 @@ __metadata: resolution: "@affine-test/affine-local@workspace:tests/affine-local" dependencies: "@affine-test/kit": "workspace:*" + "@affine-tools/cli": "workspace:*" + "@affine-tools/utils": "workspace:*" "@playwright/test": "npm:=1.51.1" + webpack: "npm:^5.98.0" languageName: unknown linkType: soft @@ -34275,7 +34278,7 @@ __metadata: languageName: node linkType: hard -"webpack@npm:^5.97.1": +"webpack@npm:^5.97.1, webpack@npm:^5.98.0": version: 5.98.0 resolution: "webpack@npm:5.98.0" dependencies: