diff --git a/.gitignore b/.gitignore index f789cacca8..0aab46e78e 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ i18n-generated.ts # Cache .eslintcache next-env.d.ts +.rollup.cache # Rust target diff --git a/apps/electron/layers/main/src/ui/index.ts b/apps/electron/layers/main/src/ui/index.ts index 4226fb38c6..261803e131 100644 --- a/apps/electron/layers/main/src/ui/index.ts +++ b/apps/electron/layers/main/src/ui/index.ts @@ -1,10 +1,17 @@ +import { join } from 'node:path'; + import { app, BrowserWindow, nativeTheme } from 'electron'; import type { NamespaceHandlers } from '../type'; import { isMacOS } from '../utils'; -import { getMetaData } from './get-meta-data'; import { getGoogleOauthCode } from './google-auth'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const handlers = require(join( + process.env.PLUGIN_DIR ?? '../../plugins', + './bookmark-block/server' +)) as NamespaceHandlers; + export const uiHandlers = { handleThemeChange: async (_, theme: (typeof nativeTheme)['themeSource']) => { nativeTheme.themeSource = theme; @@ -40,11 +47,5 @@ export const uiHandlers = { getGoogleOauthCode: async () => { return getGoogleOauthCode(); }, - getBookmarkDataByLink: async (_, url: string) => { - return getMetaData(url, { - shouldReGetHTML: metaData => { - return !metaData.title && !metaData.description; - }, - }); - }, + ...handlers, } satisfies NamespaceHandlers; diff --git a/apps/electron/package.json b/apps/electron/package.json index 3ebb015e78..234424004a 100644 --- a/apps/electron/package.json +++ b/apps/electron/package.json @@ -56,7 +56,6 @@ }, "dependencies": { "better-sqlite3": "^8.4.0", - "cheerio": "^1.0.0-rc.12", "chokidar": "^3.5.3", "electron-updater": "^5.3.0", "lodash-es": "^4.17.21", diff --git a/apps/electron/scripts/build-layers.mjs b/apps/electron/scripts/build-layers.mjs index 9d3a6d4c6a..f7e7ebdbf2 100644 --- a/apps/electron/scripts/build-layers.mjs +++ b/apps/electron/scripts/build-layers.mjs @@ -1,9 +1,12 @@ #!/usr/bin/env zx import 'zx/globals'; +import { spawnSync } from 'node:child_process'; +import { resolve } from 'node:path'; + import * as esbuild from 'esbuild'; -import { config } from './common.mjs'; +import { config, rootDir } from './common.mjs'; const NODE_ENV = process.env.NODE_ENV === 'development' ? 'development' : 'production'; @@ -17,6 +20,12 @@ async function buildLayers() { const common = config(); await esbuild.build(common.preload); + console.log('build plugins'); + spawnSync('yarn', ['build'], { + cwd: resolve(rootDir, './plugins/bookmark-block'), + stdio: 'inherit', + }); + await esbuild.build({ ...common.main, define: { diff --git a/apps/electron/scripts/common.mjs b/apps/electron/scripts/common.mjs index a363e209a1..4715d3a051 100644 --- a/apps/electron/scripts/common.mjs +++ b/apps/electron/scripts/common.mjs @@ -2,7 +2,10 @@ import { resolve } from 'node:path'; import { fileURLToPath } from 'url'; -export const root = fileURLToPath(new URL('..', import.meta.url)); +export const electronDir = fileURLToPath(new URL('..', import.meta.url)); + +export const rootDir = resolve(electronDir, '..', '..'); + export const NODE_MAJOR_VERSION = 18; // hard-coded for now: @@ -33,10 +36,13 @@ export const config = () => { return { main: { entryPoints: [ - resolve(root, './layers/main/src/index.ts'), - resolve(root, './layers/main/src/workers/merge-update.worker.ts'), + resolve(electronDir, './layers/main/src/index.ts'), + resolve( + electronDir, + './layers/main/src/workers/merge-update.worker.ts' + ), ], - outdir: resolve(root, './dist/layers/main'), + outdir: resolve(electronDir, './dist/layers/main'), bundle: true, target: `node${NODE_MAJOR_VERSION}`, platform: 'node', @@ -50,8 +56,8 @@ export const config = () => { treeShaking: true, }, preload: { - entryPoints: [resolve(root, './layers/preload/src/index.ts')], - outdir: resolve(root, './dist/layers/preload'), + entryPoints: [resolve(electronDir, './layers/preload/src/index.ts')], + outdir: resolve(electronDir, './dist/layers/preload'), bundle: true, target: `node${NODE_MAJOR_VERSION}`, platform: 'node', diff --git a/apps/electron/scripts/dev.mjs b/apps/electron/scripts/dev.mjs index 46534983d7..60e73330af 100644 --- a/apps/electron/scripts/dev.mjs +++ b/apps/electron/scripts/dev.mjs @@ -1,12 +1,12 @@ /* eslint-disable no-async-promise-executor */ import { spawn } from 'node:child_process'; import { readFileSync } from 'node:fs'; -import path from 'node:path'; +import path, { resolve } from 'node:path'; import electronPath from 'electron'; import * as esbuild from 'esbuild'; -import { config, root } from './common.mjs'; +import { config, electronDir, rootDir } from './common.mjs'; // this means we don't spawn electron windows, mainly for testing const watchMode = process.argv.includes('--watch'); @@ -21,7 +21,10 @@ const stderrFilterPatterns = [ // these are set before calling `config`, so we have a chance to override them try { - const devJson = readFileSync(path.resolve(root, './dev.json'), 'utf-8'); + const devJson = readFileSync( + path.resolve(electronDir, './dev.json'), + 'utf-8' + ); const devEnv = JSON.parse(devJson); Object.assign(process.env, devEnv); } catch (err) { @@ -65,7 +68,18 @@ function spawnOrReloadElectron() { const common = config(); -function watchPreload() { +function watchPlugins() { + const cp = spawn('yarn', ['dev'], { + cwd: resolve(rootDir, './plugins/bookmark-block'), + stdio: 'inherit', + }); + + process.once('beforeExit', () => { + cp.kill(); + }); +} + +async function watchPreload() { return new Promise(async resolve => { let initialBuild = false; const preloadBuild = await esbuild.context({ @@ -122,6 +136,7 @@ async function watchMain() { } async function main() { + watchPlugins(); await watchMain(); await watchPreload(); diff --git a/plugins/bookmark-block/package.json b/plugins/bookmark-block/package.json index 6c85b9a7de..e6b7329f2b 100644 --- a/plugins/bookmark-block/package.json +++ b/plugins/bookmark-block/package.json @@ -4,10 +4,16 @@ "main": "./src/index.ts", "module": "./src/index.ts", "exports": { - ".": "./src/index.ts" + ".": "./src/index.ts", + "./server": "./src/server.ts" + }, + "scripts": { + "build": "vite build", + "dev": "vite build --watch" }, "dependencies": { - "@toeverything/plugin-infra": "workspace:*" + "@toeverything/plugin-infra": "workspace:*", + "cheerio": "^1.0.0-rc.12" }, "devDependencies": { "react": "18.3.0-canary-16d053d59-20230506", diff --git a/plugins/bookmark-block/src/server.ts b/plugins/bookmark-block/src/server.ts new file mode 100644 index 0000000000..33fa8bd6f9 --- /dev/null +++ b/plugins/bookmark-block/src/server.ts @@ -0,0 +1,11 @@ +import { getMetaData } from './server/get-meta-data'; + +export default { + getBookmarkDataByLink: async (_: unknown, url: string) => { + return getMetaData(url, { + shouldReGetHTML: metaData => { + return !metaData.title && !metaData.description; + }, + }); + }, +}; diff --git a/apps/electron/layers/main/src/ui/get-meta-data/get-html.ts b/plugins/bookmark-block/src/server/get-meta-data/get-html.ts similarity index 100% rename from apps/electron/layers/main/src/ui/get-meta-data/get-html.ts rename to plugins/bookmark-block/src/server/get-meta-data/get-html.ts diff --git a/apps/electron/layers/main/src/ui/get-meta-data/index.ts b/plugins/bookmark-block/src/server/get-meta-data/index.ts similarity index 100% rename from apps/electron/layers/main/src/ui/get-meta-data/index.ts rename to plugins/bookmark-block/src/server/get-meta-data/index.ts diff --git a/apps/electron/layers/main/src/ui/get-meta-data/rules.ts b/plugins/bookmark-block/src/server/get-meta-data/rules.ts similarity index 100% rename from apps/electron/layers/main/src/ui/get-meta-data/rules.ts rename to plugins/bookmark-block/src/server/get-meta-data/rules.ts diff --git a/apps/electron/layers/main/src/ui/get-meta-data/types.ts b/plugins/bookmark-block/src/server/get-meta-data/types.ts similarity index 100% rename from apps/electron/layers/main/src/ui/get-meta-data/types.ts rename to plugins/bookmark-block/src/server/get-meta-data/types.ts diff --git a/apps/electron/layers/main/src/ui/get-meta-data/utils.ts b/plugins/bookmark-block/src/server/get-meta-data/utils.ts similarity index 73% rename from apps/electron/layers/main/src/ui/get-meta-data/utils.ts rename to plugins/bookmark-block/src/server/get-meta-data/utils.ts index 6f9bb8948a..ac61e810af 100644 --- a/apps/electron/layers/main/src/ui/get-meta-data/utils.ts +++ b/plugins/bookmark-block/src/server/get-meta-data/utils.ts @@ -1,10 +1,10 @@ -import urlparse from 'url'; +import { parse, resolve } from 'node:url'; export function makeUrlAbsolute(base: string, relative: string): string { - const relativeParsed = urlparse.parse(relative); + const relativeParsed = parse(relative); if (relativeParsed.host === null) { - return urlparse.resolve(base, relative); + return resolve(base, relative); } return relative; @@ -15,7 +15,7 @@ export function makeUrlSecure(url: string): string { } export function parseUrl(url: string): string { - return urlparse.parse(url).hostname || ''; + return parse(url).hostname || ''; } export function getProvider(host: string): string { diff --git a/plugins/bookmark-block/tsconfig.json b/plugins/bookmark-block/tsconfig.json index 7513033f03..c65046aba1 100644 --- a/plugins/bookmark-block/tsconfig.json +++ b/plugins/bookmark-block/tsconfig.json @@ -1,4 +1,13 @@ { "extends": "../../tsconfig.json", - "include": ["./src"] + "compilerOptions": { + "rootDir": "./src", + "types": ["electron"] + }, + "include": ["**.ts", "**.tsx"], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] } diff --git a/plugins/bookmark-block/tsconfig.node.json b/plugins/bookmark-block/tsconfig.node.json new file mode 100644 index 0000000000..cc6d1c9952 --- /dev/null +++ b/plugins/bookmark-block/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + "outDir": "lib" + }, + "include": ["vite.config.ts", "scripts"] +} diff --git a/plugins/bookmark-block/vite.config.ts b/plugins/bookmark-block/vite.config.ts new file mode 100644 index 0000000000..a23ff5e1a6 --- /dev/null +++ b/plugins/bookmark-block/vite.config.ts @@ -0,0 +1,33 @@ +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { defineConfig } from 'vite'; + +const rootDir = fileURLToPath(new URL('.', import.meta.url)); + +export default defineConfig({ + build: { + minify: false, + lib: { + entry: resolve(__dirname, 'src/server.ts'), + fileName: 'server', + formats: ['cjs'], + }, + emptyOutDir: true, + rollupOptions: { + external: ['cheerio', 'electron', 'node:url'], + output: { + dir: resolve( + rootDir, + '..', + '..', + 'apps', + 'electron', + 'dist', + 'plugins', + 'bookmark-block' + ), + }, + }, + }, +}); diff --git a/scripts/setup/build-plugins.ts b/scripts/setup/build-plugins.ts new file mode 100644 index 0000000000..89d14f6a33 --- /dev/null +++ b/scripts/setup/build-plugins.ts @@ -0,0 +1,14 @@ +import { resolve } from 'node:path'; + +import { fileURLToPath } from 'url'; +import { build } from 'vite'; +import { beforeAll } from 'vitest'; + +export const rootDir = fileURLToPath(new URL('../..', import.meta.url)); + +beforeAll(async () => { + const { default: config } = await import( + resolve(rootDir, './plugins/bookmark-block/vite.config.ts') + ); + await build(config); +}); diff --git a/vitest.config.ts b/vitest.config.ts index f4c1e9fa3f..54d3eb283b 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -6,6 +6,7 @@ import react from '@vitejs/plugin-react'; import { defineConfig } from 'vitest/config'; const rootDir = fileURLToPath(new URL('.', import.meta.url)); +const pluginOutputDir = resolve(rootDir, './apps/electron/dist/plugins'); export default defineConfig({ plugins: [react(), vanillaExtractPlugin()], @@ -16,8 +17,12 @@ export default defineConfig({ 'next/config': resolve(rootDir, './scripts/vitest/next-config-mock.ts'), }, }, + define: { + 'process.env.PLUGIN_DIR': JSON.stringify(pluginOutputDir), + }, test: { setupFiles: [ + resolve(rootDir, './scripts/setup/build-plugins.ts'), resolve(rootDir, './scripts/setup/lit.ts'), resolve(rootDir, './scripts/setup/i18n.ts'), resolve(rootDir, './scripts/setup/search.ts'), diff --git a/yarn.lock b/yarn.lock index 55b24f2b34..d54c97372b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35,6 +35,7 @@ __metadata: resolution: "@affine/bookmark-block@workspace:plugins/bookmark-block" dependencies: "@toeverything/plugin-infra": "workspace:*" + cheerio: ^1.0.0-rc.12 react: 18.3.0-canary-16d053d59-20230506 react-dom: 18.3.0-canary-16d053d59-20230506 peerDependencies: @@ -183,7 +184,6 @@ __metadata: "@types/fs-extra": ^11.0.1 "@types/uuid": ^9.0.1 better-sqlite3: ^8.4.0 - cheerio: ^1.0.0-rc.12 chokidar: ^3.5.3 cross-env: 7.0.3 electron: 25.0.0