mirror of
https://github.com/DayuanJiang/next-ai-draw-io.git
synced 2026-09-08 12:20:20 +08:00
feat(electron): bundle draw.io for offline support (#629)
* feat(electron): bundle draw.io for offline support - Download draw.io static files during CI build (v29.3.5) - Detect Electron and use local draw.io files instead of CDN - Add offline=1 parameter to disable external service calls - Skip /drawio path from i18n middleware redirect - Add public/drawio/ to .gitignore (downloaded during build) This allows the Electron app to work completely offline. * chore: bump version to 0.4.12-beta.3 for offline test * fix(electron): ad-hoc sign macOS app for bundled draw.io compatibility * chore: bump version to 0.4.12-beta.4 for ad-hoc sign test * fix(electron): disable electron-builder signing to use custom ad-hoc signing * chore: bump version to 0.4.12-beta.5
This commit is contained in:
@@ -34,6 +34,15 @@ jobs:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
|
||||
- name: Download draw.io static files for offline use
|
||||
run: |
|
||||
rm -rf public/drawio
|
||||
git clone --depth 1 --branch v29.3.5 https://github.com/jgraph/drawio.git /tmp/drawio
|
||||
mkdir -p public/drawio
|
||||
cp -r /tmp/drawio/src/main/webapp/* public/drawio/
|
||||
rm -rf public/drawio/WEB-INF
|
||||
rm -rf public/drawio/META-INF
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
@@ -57,6 +66,16 @@ jobs:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
|
||||
- name: Download draw.io static files for offline use
|
||||
shell: bash
|
||||
run: |
|
||||
rm -rf public/drawio
|
||||
git clone --depth 1 --branch v29.3.5 https://github.com/jgraph/drawio.git /tmp/drawio
|
||||
mkdir -p public/drawio
|
||||
cp -r /tmp/drawio/src/main/webapp/* public/drawio/
|
||||
rm -rf public/drawio/WEB-INF
|
||||
rm -rf public/drawio/META-INF
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ push-via-ec2.sh
|
||||
/dist-electron/
|
||||
/release/
|
||||
/electron-standalone/
|
||||
# Draw.io static files (downloaded during CI build)
|
||||
public/drawio/
|
||||
*.dmg
|
||||
*.exe
|
||||
*.AppImage
|
||||
|
||||
+20
-4
@@ -12,9 +12,6 @@ import {
|
||||
import { useDiagram } from "@/contexts/diagram-context"
|
||||
import { i18n, type Locale } from "@/lib/i18n/config"
|
||||
|
||||
const drawioBaseUrl =
|
||||
process.env.NEXT_PUBLIC_DRAWIO_BASE_URL || "https://embed.diagrams.net"
|
||||
|
||||
export default function Home() {
|
||||
const { drawioRef, handleDiagramExport, onDrawioLoad, resetDrawioReady } =
|
||||
useDiagram()
|
||||
@@ -28,6 +25,10 @@ export default function Home() {
|
||||
const [darkMode, setDarkMode] = useState(false)
|
||||
const [isLoaded, setIsLoaded] = useState(false)
|
||||
const [isDrawioReady, setIsDrawioReady] = useState(false)
|
||||
const [isElectron, setIsElectron] = useState(false)
|
||||
const [drawioBaseUrl, setDrawioBaseUrl] = useState(
|
||||
process.env.NEXT_PUBLIC_DRAWIO_BASE_URL || "https://embed.diagrams.net",
|
||||
)
|
||||
|
||||
const chatPanelRef = useRef<ImperativePanelHandle>(null)
|
||||
const isMobileRef = useRef(false)
|
||||
@@ -64,6 +65,17 @@ export default function Home() {
|
||||
document.documentElement.classList.toggle("dark", prefersDark)
|
||||
}
|
||||
|
||||
// Detect Electron and use bundled draw.io files for offline use
|
||||
// Note: react-drawio uses `new URL(baseUrl)` so we need absolute URL
|
||||
// Include /index.html because Next.js doesn't auto-serve index.html for directories
|
||||
const electronDetected =
|
||||
!process.env.NEXT_PUBLIC_DRAWIO_BASE_URL &&
|
||||
!!(window as unknown as { electronAPI?: unknown }).electronAPI
|
||||
if (electronDetected) {
|
||||
setIsElectron(true)
|
||||
setDrawioBaseUrl(`${window.location.origin}/drawio/index.html`)
|
||||
}
|
||||
|
||||
setIsLoaded(true)
|
||||
}, [pathname, router])
|
||||
|
||||
@@ -160,7 +172,7 @@ export default function Home() {
|
||||
className={`h-full w-full ${isDrawioReady ? "" : "invisible absolute inset-0"}`}
|
||||
>
|
||||
<DrawIoEmbed
|
||||
key={`${drawioUi}-${darkMode}-${currentLang}`}
|
||||
key={`${drawioUi}-${darkMode}-${currentLang}-${isElectron}`}
|
||||
ref={drawioRef}
|
||||
onExport={handleDiagramExport}
|
||||
onLoad={handleDrawioLoad}
|
||||
@@ -174,6 +186,10 @@ export default function Home() {
|
||||
noExitBtn: true,
|
||||
dark: darkMode,
|
||||
lang: currentLang,
|
||||
// Enable offline mode in Electron to disable external service calls
|
||||
...(isElectron && {
|
||||
offline: true,
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -37,10 +37,11 @@ mac:
|
||||
arch:
|
||||
- x64
|
||||
- arm64
|
||||
hardenedRuntime: true
|
||||
# Disable electron-builder's signing - we use custom ad-hoc signing in afterPack
|
||||
# to properly sign nested bundles with --deep flag for bundled draw.io files
|
||||
identity: null
|
||||
hardenedRuntime: false
|
||||
gatekeeperAssess: false
|
||||
entitlements: resources/entitlements.mac.plist
|
||||
entitlementsInherit: resources/entitlements.mac.plist
|
||||
|
||||
dmg:
|
||||
contents:
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "next-ai-draw-io",
|
||||
"version": "0.4.11",
|
||||
"version": "0.4.12-beta.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "next-ai-draw-io",
|
||||
"version": "0.4.11",
|
||||
"version": "0.4.12-beta.5",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@ai-sdk/amazon-bedrock": "^4.0.1",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-ai-draw-io",
|
||||
"version": "0.4.11",
|
||||
"version": "0.4.12-beta.5",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"main": "dist-electron/main/index.js",
|
||||
|
||||
@@ -31,6 +31,7 @@ export function proxy(request: NextRequest) {
|
||||
if (
|
||||
pathname.startsWith("/api/") ||
|
||||
pathname.startsWith("/_next/") ||
|
||||
pathname.startsWith("/drawio") ||
|
||||
pathname.includes("/favicon") ||
|
||||
/\.(.*)$/.test(pathname)
|
||||
) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* electron-builder afterPack hook
|
||||
* Copies node_modules to the standalone directory in the packaged app
|
||||
* and ad-hoc signs macOS apps for offline draw.io bundle compatibility
|
||||
*/
|
||||
|
||||
const {
|
||||
@@ -12,6 +13,7 @@ const {
|
||||
statSync,
|
||||
} = require("fs")
|
||||
const path = require("path")
|
||||
const { execSync } = require("child_process")
|
||||
|
||||
/**
|
||||
* Copy directory recursively, converting symlinks to regular files/directories.
|
||||
@@ -80,4 +82,22 @@ module.exports = async (context) => {
|
||||
"Ensure 'npm run electron:prepare' was run before building.",
|
||||
)
|
||||
}
|
||||
|
||||
// Ad-hoc sign macOS apps to fix signature issues with bundled draw.io files
|
||||
if (context.packager.platform.name === "mac") {
|
||||
const appPath = path.join(
|
||||
appOutDir,
|
||||
`${context.packager.appInfo.productFilename}.app`,
|
||||
)
|
||||
console.log(`[afterPack] Ad-hoc signing macOS app: ${appPath}`)
|
||||
try {
|
||||
execSync(`codesign --force --deep --sign - "${appPath}"`, {
|
||||
stdio: "inherit",
|
||||
})
|
||||
console.log("[afterPack] Ad-hoc signing completed successfully")
|
||||
} catch (error) {
|
||||
console.error("[afterPack] Ad-hoc signing failed:", error.message)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user