|
|
||
|---|---|---|
| .. | ||
| components | ||
| io-managers | ||
| state-providers | ||
| utility-functions | ||
| App.svelte | ||
| README.md | ||
| editor.ts | ||
| global.d.ts | ||
| icons.ts | ||
| main.ts | ||
| subscription-router.ts | ||
| vite-env-override.d.ts | ||
| vite-env.d.ts | ||
README.md
Overview of /frontend/src/
Svelte components: components/
Svelte components that build the Graphite editor GUI. These each contain a TypeScript section, a Svelte-templated HTML template section, and an SCSS stylesheet section. The aim is to avoid implementing much editor business logic here, just enough to make things interactive and communicate to the backend where the real business logic should occur.
I/O managers: io-managers/
TypeScript files which manage the input/output of browser APIs and link this functionality with the editor backend. These files subscribe to backend events to execute JS APIs, and in response to these APIs or user interactions, they may call functions into the backend (defined in /frontend/wasm/editor_api.rs).
Each I/O manager is a self-contained module where one instance is created in Editor.svelte when it's mounted to the DOM at app startup.
During development when HMR (hot-module replacement) occurs, these are also unmounted to clean up after themselves, so they can be mounted again with the updated code. Therefore, any side-effects that these managers cause (e.g. adding event listeners to the page) need a destructor function that cleans them up. The destructor function, when applicable, is returned by the module and automatically called in Editor.svelte on unmount.
State providers: state-providers/
TypeScript files which provide reactive state and importable functions to Svelte components. Each module defines a Svelte writable store const { subscribe, update } = writable({ .. }); and exports the subscribe method from the module in the returned object. Other functions may also be defined in the module and exported after subscribe, which provide a way for Svelte components to call functions to manipulate the state.
In Editor.svelte, an instance of each of these are given to Svelte's setContext() function. This allows any component to access the state provider instance using const exampleStateProvider = getContext<ExampleStateProvider>("exampleStateProvider");.
I/O managers vs. state providers
Some state providers, similarly to I/O managers, may subscribe to backend events, call functions from editor_api.rs into the backend, and interact with browser APIs and user input. The difference is that state providers are meant to be made available to components via getContext() to use them for reactive state, while I/O managers are meant to be self-contained systems that operate for the lifetime of the application and aren't touched by Svelte components.
Utility functions: utility-functions/
TypeScript files which define and export individual helper functions for use elsewhere in the codebase. These files should not persist state outside each function.
Wasm editor: editor.ts
Instantiates the Wasm and editor backend instances. The function initWasm() asynchronously constructs and initializes an instance of the Wasm bindings JS module provided by wasm-bindgen/wasm-pack. The function createEditor() constructs an instance of the editor backend. In theory there could be multiple editor instances sharing the same Wasm module instance. The function returns an object where raw is the Wasm memory, handle provides access to callable backend functions, and subscriptions is the subscription router (described below).
initWasm() occurs in main.ts right before the Svelte application is mounted, then createEditor() is run in Editor.svelte during the Svelte app's creation. Similarly to the state providers described above, the editor is given via setContext() so other components can get it via getContext and call functions on editor.handle or editor.subscriptions.
Subscription router: subscription-router.ts
Associates messages from the backend with subscribers in the frontend, and routes messages to subscriber callbacks. This module provides a subscribeFrontendMessage(messageType, callback) function which JS code throughout the frontend can call to be registered as the exclusive handler for a chosen message type. The router's other function, handleFrontendMessage(messageType, messageData), is called via the callback passed to EditorHandle.create() in editor.ts when the backend sends a FrontendMessage. When this occurs, the subscription router delivers the message to the subscriber by executing its registered callback function.
Svelte app entry point: App.svelte
The entry point for the Svelte application.
Editor base instance: Editor.svelte
This is where we define global CSS style rules, create/destroy the editor instance, construct/destruct the I/O managers, and construct and setContext() the state providers.
Global type augmentations: global.d.ts
Extends built-in browser type definitions using TypeScript's interface merging. This includes Graphite's custom properties on the window object, custom events like pointerlockmove, and experimental browser APIs not yet in TypeScript's standard library. New custom events or non-standard browser APIs used by the frontend should be declared here.
JS bundle entry point: main.ts
The entry point for the entire project's code bundle. Here we simply mount the Svelte application with export default mount(App, { target: document.body });.