reduce installer size 50% and app bundle size by 30%

This commit is contained in:
Siddharth
2025-11-23 16:49:53 -07:00
parent 0d5c4529d1
commit b181546ad3
15 changed files with 113 additions and 43 deletions
+11 -1
View File
@@ -6,12 +6,19 @@
"productName": "Openscreen",
"npmRebuild": true,
"buildDependenciesFromSource": true,
"compression": "maximum",
"directories": {
"output": "release/${version}"
},
"files": [
"dist",
"dist-electron"
"dist-electron",
"!*.png",
"!preview*.png",
"!*.md",
"!README.md",
"!CONTRIBUTING.md",
"!LICENSE"
],
"extraResources": [
{
@@ -19,6 +26,9 @@
"to": "assets/wallpapers"
}
],
"asarUnpack": [
"**/node_modules/uiohook-napi/**/*"
],
"mac": {
"target": [
"dmg"
+38
View File
@@ -47,6 +47,7 @@
"eslint-plugin-react-refresh": "^0.4.5",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.18",
"terser": "^5.44.1",
"typescript": "^5.2.2",
"vite": "^5.1.6",
"vite-plugin-electron": "^0.28.6",
@@ -1447,6 +1448,17 @@
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
@@ -9832,6 +9844,32 @@
"node": ">= 10.0.0"
}
},
"node_modules/terser": {
"version": "5.44.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+1
View File
@@ -50,6 +50,7 @@
"eslint-plugin-react-refresh": "^0.4.5",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.18",
"terser": "^5.44.1",
"typescript": "^5.2.2",
"vite": "^5.1.6",
"vite-plugin-electron": "^0.28.6",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 MiB

After

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 MiB

After

Width:  |  Height:  |  Size: 827 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 MiB

After

Width:  |  Height:  |  Size: 524 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 MiB

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 MiB

After

Width:  |  Height:  |  Size: 897 KiB

+19 -19
View File
@@ -1,7 +1,7 @@
import type React from "react";
import { useEffect, useRef, useImperativeHandle, forwardRef, useState, useMemo, useCallback } from "react";
import { getAssetPath } from "@/lib/assetPath";
import * as PIXI from 'pixi.js';
import { Application, Container, Sprite, Graphics, BlurFilter, Texture, VideoSource } from 'pixi.js';
import { ZOOM_DEPTH_SCALES, type ZoomRegion, type ZoomFocus, type ZoomDepth } from "./types";
import { DEFAULT_FOCUS, SMOOTHING_FACTOR, MIN_DELTA } from "./videoPlayback/constants";
import { clamp01 } from "./videoPlayback/mathUtils";
@@ -31,9 +31,9 @@ interface VideoPlaybackProps {
export interface VideoPlaybackRef {
video: HTMLVideoElement | null;
app: PIXI.Application | null;
videoSprite: PIXI.Sprite | null;
videoContainer: PIXI.Container | null;
app: Application | null;
videoSprite: Sprite | null;
videoContainer: Container | null;
play: () => Promise<void>;
pause: () => void;
}
@@ -56,10 +56,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
}, ref) => {
const videoRef = useRef<HTMLVideoElement | null>(null);
const containerRef = useRef<HTMLDivElement | null>(null);
const appRef = useRef<PIXI.Application | null>(null);
const videoSpriteRef = useRef<PIXI.Sprite | null>(null);
const videoContainerRef = useRef<PIXI.Container | null>(null);
const cameraContainerRef = useRef<PIXI.Container | null>(null);
const appRef = useRef<Application | null>(null);
const videoSpriteRef = useRef<Sprite | null>(null);
const videoContainerRef = useRef<Container | null>(null);
const cameraContainerRef = useRef<Container | null>(null);
const timeUpdateAnimationRef = useRef<number | null>(null);
const [pixiReady, setPixiReady] = useState(false);
const [videoReady, setVideoReady] = useState(false);
@@ -69,7 +69,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
const zoomRegionsRef = useRef<ZoomRegion[]>([]);
const selectedZoomIdRef = useRef<string | null>(null);
const animationStateRef = useRef({ scale: 1, focusX: DEFAULT_FOCUS.cx, focusY: DEFAULT_FOCUS.cy });
const blurFilterRef = useRef<PIXI.BlurFilter | null>(null);
const blurFilterRef = useRef<BlurFilter | null>(null);
const isDraggingFocusRef = useRef(false);
const stageSizeRef = useRef({ width: 0, height: 0 });
const videoSizeRef = useRef({ width: 0, height: 0 });
@@ -77,7 +77,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
const baseOffsetRef = useRef({ x: 0, y: 0 });
const baseMaskRef = useRef({ x: 0, y: 0, width: 0, height: 0 });
const cropBoundsRef = useRef({ startX: 0, endX: 0, startY: 0, endY: 0 });
const maskGraphicsRef = useRef<PIXI.Graphics | null>(null);
const maskGraphicsRef = useRef<Graphics | null>(null);
const isPlayingRef = useRef(isPlaying);
const isSeekingRef = useRef(false);
const allowPlaybackRef = useRef(false);
@@ -398,10 +398,10 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
if (!container) return;
let mounted = true;
let app: PIXI.Application | null = null;
let app: Application | null = null;
(async () => {
app = new PIXI.Application();
app = new Application();
await app.init({
width: container.clientWidth,
@@ -423,12 +423,12 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
container.appendChild(app.canvas);
// Camera container - this will be scaled/positioned for zoom
const cameraContainer = new PIXI.Container();
const cameraContainer = new Container();
cameraContainerRef.current = cameraContainer;
app.stage.addChild(cameraContainer);
// Video container - holds the masked video sprite
const videoContainer = new PIXI.Container();
const videoContainer = new Container();
videoContainerRef.current = videoContainer;
cameraContainer.addChild(videoContainer);
@@ -468,19 +468,19 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
if (!video || !app || !videoContainer) return;
if (video.videoWidth === 0 || video.videoHeight === 0) return;
const source = PIXI.VideoSource.from(video);
const source = VideoSource.from(video);
if ('autoPlay' in source) {
(source as { autoPlay?: boolean }).autoPlay = false;
}
if ('autoUpdate' in source) {
(source as { autoUpdate?: boolean }).autoUpdate = true;
}
const videoTexture = PIXI.Texture.from(source);
const videoTexture = Texture.from(source);
const videoSprite = new PIXI.Sprite(videoTexture);
const videoSprite = new Sprite(videoTexture);
videoSpriteRef.current = videoSprite;
const maskGraphics = new PIXI.Graphics();
const maskGraphics = new Graphics();
videoContainer.addChild(videoSprite);
videoContainer.addChild(maskGraphics);
videoContainer.mask = maskGraphics;
@@ -492,7 +492,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(({
focusY: DEFAULT_FOCUS.cy,
};
const blurFilter = new PIXI.BlurFilter();
const blurFilter = new BlurFilter();
blurFilter.quality = 3;
blurFilter.resolution = app.renderer.resolution;
blurFilter.blur = 0;
@@ -1,12 +1,12 @@
import * as PIXI from 'pixi.js';
import { Application, Sprite, Graphics } from 'pixi.js';
import { VIEWPORT_SCALE } from "./constants";
import type { CropRegion } from '../types';
interface LayoutParams {
container: HTMLDivElement;
app: PIXI.Application;
videoSprite: PIXI.Sprite;
maskGraphics: PIXI.Graphics;
app: Application;
videoSprite: Sprite;
maskGraphics: Graphics;
videoElement: HTMLVideoElement;
cropRegion?: CropRegion;
lockedVideoDimensions?: { width: number; height: number } | null;
@@ -1,8 +1,8 @@
import * as PIXI from 'pixi.js';
import { Container, BlurFilter } from 'pixi.js';
interface TransformParams {
cameraContainer: PIXI.Container;
blurFilter: PIXI.BlurFilter | null;
cameraContainer: Container;
blurFilter: BlurFilter | null;
stageSize: { width: number; height: number };
baseMask: { x: number; y: number; width: number; height: number };
zoomScale: number;
+16 -16
View File
@@ -1,4 +1,4 @@
import * as PIXI from 'pixi.js';
import { Application, Container, Sprite, Graphics, BlurFilter, Texture } from 'pixi.js';
import type { ZoomRegion, CropRegion } from '@/components/video-editor/types';
import { ZOOM_DEPTH_SCALES } from '@/components/video-editor/types';
import { findDominantRegion } from '@/components/video-editor/videoPlayback/zoomRegionUtils';
@@ -27,13 +27,13 @@ interface AnimationState {
// Renders video frames with all effects (background, zoom, crop, blur, shadow) to an offscreen canvas for export.
export class FrameRenderer {
private app: PIXI.Application | null = null;
private cameraContainer: PIXI.Container | null = null;
private videoContainer: PIXI.Container | null = null;
private videoSprite: PIXI.Sprite | null = null;
private backgroundSprite: PIXI.Sprite | null = null;
private maskGraphics: PIXI.Graphics | null = null;
private blurFilter: PIXI.BlurFilter | null = null;
private app: Application | null = null;
private cameraContainer: Container | null = null;
private videoContainer: Container | null = null;
private videoSprite: Sprite | null = null;
private backgroundSprite: Sprite | null = null;
private maskGraphics: Graphics | null = null;
private blurFilter: BlurFilter | null = null;
private shadowCanvas: HTMLCanvasElement | null = null;
private shadowCtx: CanvasRenderingContext2D | null = null;
private compositeCanvas: HTMLCanvasElement | null = null;
@@ -70,7 +70,7 @@ export class FrameRenderer {
}
// Initialize PixiJS with optimized settings for export performance
this.app = new PIXI.Application();
this.app = new Application();
await this.app.init({
canvas,
width: this.config.width,
@@ -82,8 +82,8 @@ export class FrameRenderer {
});
// Setup containers
this.cameraContainer = new PIXI.Container();
this.videoContainer = new PIXI.Container();
this.cameraContainer = new Container();
this.videoContainer = new Container();
this.app.stage.addChild(this.cameraContainer);
this.cameraContainer.addChild(this.videoContainer);
@@ -91,7 +91,7 @@ export class FrameRenderer {
await this.setupBackground();
// Setup blur filter for video container
this.blurFilter = new PIXI.BlurFilter();
this.blurFilter = new BlurFilter();
this.blurFilter.quality = 3;
this.blurFilter.resolution = this.app.renderer.resolution;
this.blurFilter.blur = 0;
@@ -120,7 +120,7 @@ export class FrameRenderer {
}
// Setup mask
this.maskGraphics = new PIXI.Graphics();
this.maskGraphics = new Graphics();
this.videoContainer.addChild(this.maskGraphics);
this.videoContainer.mask = this.maskGraphics;
}
@@ -251,13 +251,13 @@ export class FrameRenderer {
// Create or update video sprite from VideoFrame
if (!this.videoSprite) {
const texture = PIXI.Texture.from(videoFrame as any);
this.videoSprite = new PIXI.Sprite(texture);
const texture = Texture.from(videoFrame as any);
this.videoSprite = new Sprite(texture);
this.videoContainer.addChild(this.videoSprite);
} else {
// Destroy old texture to avoid memory leaks, then create new one
const oldTexture = this.videoSprite.texture;
const newTexture = PIXI.Texture.from(videoFrame as any);
const newTexture = Texture.from(videoFrame as any);
this.videoSprite.texture = newTexture;
oldTexture.destroy(true);
}
+21
View File
@@ -39,4 +39,25 @@ export default defineConfig({
'@': path.resolve(__dirname, 'src'),
},
},
build: {
target: 'esnext',
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log', 'console.debug']
}
},
rollupOptions: {
output: {
manualChunks: {
'pixi': ['pixi.js'],
'react-vendor': ['react', 'react-dom'],
'video-processing': ['mediabunny', 'mp4box', '@fix-webm-duration/fix']
}
}
},
chunkSizeWarningLimit: 1000
}
})