Bridge @awacloud/fw with a Vite build : exposes virtual modules that bundle a preset or a side-bundle, and optionally injects the sanity layer.
Install
The plugin lives inside @awacloud/fw itself — no separate install needed once the framework is published.
npm i @awacloud/fw
Usage
// vite.config.js
import { defineConfig } from 'vite';
import fw from '@awacloud/fw/vite';
export default defineConfig({
plugins: [
fw({
preset: 'site-interactive',
sideBundles: ['crypto-basic', 'realtime'],
sanity: 'base' // or 'community', 'lockdown', or false
})
]
});
// app/main.js
import { runtime } from 'virtual:@awacloud/fw/preset/site-interactive';
const hex = runtime.resolve('hex');
console.log(hex.fromBytes(new Uint8Array([72])));
// Side-bundle : dynamically imported, Vite code-splits it automatically.
async function login() {
const cryptoBasic = await import('virtual:@awacloud/fw/side-bundle/crypto-basic');
cryptoBasic.install(runtime);
const hmac = runtime.resolve('hmac');
// ...
}
Virtual modules
| ID | Exports |
|---|---|
virtual:@awacloud/fw/preset/<name> |
runtime (pre-registered), moduleNames |
virtual:@awacloud/fw/side-bundle/<name> |
install(runtime), modules, moduleNames |
Available preset names match the keys of presets in fw.config.json (minimal, core, site, site-interactive, spa, pwa) plus the synthetic full (everything in src/).
Available side-bundle names match the keys of sideBundles in fw.config.json (realtime, crypto-basic, crypto-identity, crypto-advanced, compress-heavy, sensors, text-advanced, structures-advanced).
How tree-shaking works
The plugin emits code with direct subpath imports :
// generated by the plugin
import { ModuleRuntime } from '@awacloud/fw/core/runtime';
import { sanitize } from '@awacloud/fw/dom/rendering/sanitize.js';
import { hex } from '@awacloud/fw/io/codec/hex.js';
export const runtime = new ModuleRuntime();
runtime.registerAllDeep([sanitize, hex]);
Each module file imports its own dependencies statically (the deps field is the runtime mirror of those imports). Rollup follows the import graph and pulls only what sanitize and hex actually need — parser.js, render.js, secPolicy.js, etc. — never the full core/modules catalogue.
Tree-shaking is preset-level, not within a preset. When the plugin emits
registerAllDeep([a, b, c]) for a preset, all three bindings are statically
referenced ; Rollup cannot drop c even if runtime.resolve('c') is never
called downstream. Picking a smaller preset (or composing by hand) is the
only way to shrink the bundle further.
You can write the same code by hand if you don't want a virtual import :
import { ModuleRuntime } from '@awacloud/fw/core/runtime';
import { sanitize } from '@awacloud/fw/dom/rendering/sanitize.js';
const runtime = new ModuleRuntime();
runtime.registerDeep(sanitize);
TypeScript — transparent narrowing
Add this once in any .ts of your project (e.g. src/vite-env.d.ts) :
/// <reference types="@awacloud/fw/vite-env" />
The runtime exported by virtual:@awacloud/fw/preset/<name> is then typed as a
TypedModuleRuntime, so resolve narrows by module name with no extra step :
import { runtime } from 'virtual:@awacloud/fw/preset/site-interactive';
const hex = runtime.resolve('hex'); // typed — no asTyped, no <T>
This costs nothing at runtime and nothing in the bundle (the name→type map is
type-only and erased). See docs/guide/typescript.md.
Notes
- Source of truth : both the autonomous build (
tools/fw-bundler) and this Vite plugin consume the samefw.config.jsonfile, so they cannot drift. - Catalog scan : the plugin scans
src/once at instantiation to map module names → file paths. Cost is paid once per Vite session. - Dev-session config/catalog reload — no restart needed : in
vite dev, editingfw.config.json(default path or anoptions.configPathoverride) or regenerating the committed catalog (bun run integrations:catalog) is picked up automatically — the plugin watches both files via Vite's ownconfigureServerdev-server hook, re-validates and swaps its cached state, invalidates the affected virtual modules, and triggers a full browser reload. No manual "restart the dev server" step is required for either input. This is dev-only :vite buildnever callsconfigureServer, so production/build output is byte-identical to before this behaviour was added — the cache is still built exactly once, at plugin construction, and never re-read outside a running dev session. A malformed edit (invalid JSON, an unknown preset/side-bundle) logs an error to the Vite console and leaves the previously-working cache in place, rather than crashing the dev session. - Sanity injection : when
sanity: 'base'orsanity: 'community'is set, the plugin injectsimport { applyBase } from '@awacloud/fw/sanity/base'; applyBase();(resp.applyCommunity) as the first<head>script of every HTML page (viatransformIndexHtml,head-prepend). Whensanity: 'lockdown'is set, the snippet isimport { lockdown } from '@awacloud/fw/sanity/lockdown'; lockdown();— becauselockdown.jsis an explicit-call ES module, not a side-effect IIFE. Module scripts run in document order, so the import+invocation executes before any app entry. This is client-only and works identically invite devandvite build. - Webpack / Rollup / esbuild : equivalent plugins are planned. The current Vite plugin is the reference implementation and reads the same
config.json— porting amounts to wiringresolveId/loadhooks of the target bundler.