Axion is a versatile server-side framework designed for modular and adaptable web applications. It leverages Deno's capabilities to provide a robust environment for building scalable and efficient web services.
The main orchestrator initializes and manages two core components:
- File Loader: A worker responsible for handling file operations.
- API Service: A worker that processes API requests.
These components are initialized sequentially, with built-in error handling and restart mechanisms.
The File Loader is responsible for:
- Loading and caching project configurations (axion.config.json and deno.json).
- Handling file requests with support for various loaders (local, GitHub, etc.).
- Implementing caching strategies for improved performance.
The API Service:
- Loads project-specific adapters and configurations.
- Utilizes a proxy to handle incoming requests.
- Incorporates dynamic loading of modules based on request paths.
-
Modular Architecture: The framework is designed with modularity in mind, allowing easy extension and customization.
-
Dynamic Configuration: Project-specific configurations (axion.config.json and deno.json) are dynamically loaded and applied.
-
Isolation: The framework uses Deno's worker capabilities to isolate different components, enhancing stability and resource management.
-
Caching: Implements intelligent caching mechanisms for configurations and file content to optimize performance.
-
Adaptable Routing: Supports dynamic routing based on file structure and configurations.
-
Environment Flexibility: Easily adaptable to different environments (local, production) through environment variables.
-
Error Handling: Robust error handling and reporting mechanisms are in place throughout the system.
- The main orchestrator initializes the File Loader.
- Once the File Loader is ready, the API Service is initialized.
- Incoming requests are handled by the API Service.
- The API Service uses the File Loader to fetch necessary files and configurations.
- Requests are processed using the appropriate modules and adapters.
- Responses are sent back to the client.
This architecture allows for a flexible and scalable system that can adapt to various project requirements while maintaining performance and stability.
Axion is a versatile server-side framework designed for building modular and adaptable web applications. It leverages Deno's capabilities to provide a robust environment for scalable and efficient web services.
The main orchestrator initializes and manages two core components:
- File Loader: A worker responsible for handling file operations.
- API Service: A worker that processes API requests.
These components are initialized sequentially, with built-in error handling and restart mechanisms.
The server component creates and manages the HTTP server:
- Handles incoming requests
- Manages CORS and OPTIONS requests
- Routes requests to the appropriate handler
Configuration options:
port
: Server port number (default: 8000)
The proxy acts as the main request handler and manages isolates:
Key functionalities:
- Parses incoming request URLs
- Determines appropriate isolates for handling requests
- Creates, upgrades, and manages isolate lifecycles
- Forwards requests to isolates and streams responses back to clients
Configuration options:
isolateType
: Type of isolate to use (default: 'subprocess')formatImportUrl
: Custom function to format import URLsmapFilePathToIsolateId
: Custom function to map file paths to isolate IDsshouldUpgradeAfter
: Timestamp for isolate upgradesisolateMaxIdleTime
: Maximum idle time before terminating an isolatedebug
: Enable debug logging
Responsible for loading and processing files from various sources:
- Loads file content based on request paths
- Handles redirects
- Processes and transforms file content
- Sets appropriate content types
Configuration options:
loaderType
: Type of loader to use (e.g., "local", "github")functionsDir
: Directory containing application functionsdirEntrypoint
: Default entrypoint file name
Handles regular JavaScript/TypeScript isolate initialization and execution:
Handles JSX-specific isolate initialization and execution:
Both isolate adapters:
- Initialize the execution environment
- Set up global variables
- Configure caching mechanisms
Configuration options:
port
: Port number for the isolate serverprojectId
: Unique identifier for the project
Responsible for executing modules within isolates:
- Loads and executes modules
- Handles server-side rendering for JSX components
- Processes CSS and injects it into rendered HTML
- Manages middleware execution and dependency injection
Configuration options:
loader
: Custom module loader functionfunctionsDir
: Directory containing application functionsdependencies
: External dependencies to be injectedisJSX
: Flag indicating whether to use JSX processing
- The server receives an incoming HTTP request.
- The request is passed to the proxy component.
- The proxy determines the appropriate isolate to handle the request:
- If an isolate exists and is ready, it's used.
- If no isolate exists or needs upgrading, a new one is created or upgraded.
- The proxy forwards the request to the chosen isolate.
- The isolate processes the request:
- For JSX components, server-side rendering is performed.
- For regular modules, the appropriate HTTP method handler is executed.
- The response is processed and streamed back through the proxy to the client.
- Isolates are created on-demand based on incoming requests.
- Each isolate is associated with a specific file path and runs in a sandboxed environment.
- Isolates can be upgraded if they become outdated (based on
shouldUpgradeAfter
config). - Idle isolates are terminated after a configurable period (
isolateMaxIdleTime
) to manage resources efficiently.
- File content and processed data are cached to improve performance.
- Isolate metadata is cached to avoid unnecessary recreation of isolates.
- CSS processing results are cached and streamed asynchronously for optimal performance.
Adapters in the Axion Framework provide a powerful mechanism to customize and extend the behavior of various components. They are loaded dynamically and can modify the configuration and behavior of the system.
Adapters are typically located in the ${functionsDir}/adapters
directory. They are loaded dynamically when the API service initializes.
An adapter is a module that exports a default function. This function receives the current configuration and can modify or extend it.
Adapters can export and modify the following properties and functions:
-
loaderConfig
: Configures the file loader behavior.username
: Sets the username for the file loader URL, that is used by file-loader to determine the source for serving the files. Has the following format:${provider}--${org}--${repo}--${branch}--${environment}
.- By default, it'll consider
provider
=local
, and load files for local filesystem.
password
: Sets the password for the file loader URL (if applicable).
example: for using the github file-loader and dynamically load a remote repository, you can use:
// For GitHub loader const fileLoaderUrl = new URL('https://your-file-loader-url'); loaderConfig: { username: 'github--owner--repo--branch--environment'; password: '<github_auth_token>' }
-
shouldUpgradeAfter
: A timestamp indicating when isolates should be upgraded. Instead of needing to deploy an application (if you are using any remote file-loader option like github), you unly need to update this variable in order to update your app to the newest version. Before redirecting trafic, it performs a healthchek, and if it passes, traffic is redirected to the newly instantiated isolate. Else, it goes back to the previous healthy isolate serving the requests. -
isolateType
: The 'isolateType' property is a crucial configuration option in Axion Functions that determines how isolated environments (isolates) are created for executing code. This property can be customized in the adapters.ts file and is implemented in the isolateFactory.ts file within the proxy directory.
There are two main types of isolates supported:
- Subprocess Isolate
- Web Worker Isolate
Let's break down how these are defined and used:
- In adapters.ts, the 'isolateType' is set:
export default (adapters: any) => {
// other code here...
return { ...adapters, isolateType:'worker' } // can either be 'worker' or 'subprocess'
}
Let's look at the key differences between these two types:
- Subprocess Isolate:
- Created using Deno.Command
- Runs as a separate process
- Has more flexibility in terms of permissions and environment variables
- Suitable for heavier workloads or when full process isolation is needed
- Web Worker Isolate:
- Created using the Web Worker API
- Runs in a separate thread within the same process
- Lighter weight and faster to create
- Suitable for most use cases, especially when quick startup and lower resource usage are priorities
The choice between these two types allows developers to optimize their application based on their specific needs. For most cases, the Web Worker Isolate (default) provides a good balance of isolation and performance. However, for situations requiring stricter isolation or specific system-level permissions, the Subprocess Isolate can be used.
To change the isolate type, you would modify the 'isolateType' property in the adapters.ts file. This flexibility allows Axion Functions to cater to a wide range of use cases and performance requirements.
-
In
api.ts
:- Adapters are loaded from the
functionsDir/adapters
path. - The adapter function is called with the current configuration.
- The returned configuration is used to update the system behavior.
- Adapters are loaded from the
-
In the Proxy component:
- Custom properties from the adapter are accessible in the
config
object. - These properties can be used to modify the behavior of isolates, routing, or any other aspect of request handling.
- Custom properties from the adapter are accessible in the
Here's a simple example of an adapter:
export default async function adapter(config: any) {
return {
...config,
loaderConfig: {
username: 'custom-loader',
password: 'secret-password'
},
shouldUpgradeAfter: Date.now() + 3600000, // Upgrade after 1 hour
isolateType:'subprocess',
mapFilePathToIsolateId: ({formattedFilePath})=>formattedFileUrl) // one isolate per file
};
}
The Axion Framework allows for extensive configuration and customization:
-
Project-wide configuration:
adapters.{ts|js}
: Overrides default behaviors of axion-functions.axion.config.json
: Defines project-wide settingsdeno.json
: Configures Deno-specific options
-
Custom loaders:
- Implement custom file loaders by extending the base loader functionality
The file-loader will parse the username string to determine the loader type and additional parameters. The password field can be used for authentication or as a secret key for the custom loader.
-
Middleware:
- Define custom middleware functions to be executed before and after module execution
-
Isolate management:
- Customize isolate creation, upgrading, and termination strategies by modifying the proxy logic
-
Module execution:
- Implement custom module loaders and execution strategies
-
Caching:
- Configure caching strategies for file content, isolate metadata, and execution results
The Axion Framework provides a flexible and scalable architecture for building web applications. Its modular design, isolate-based execution model, and extensive configuration options allow developers to create efficient and secure server-side applications while maintaining the ability to customize and extend the framework's capabilities.