You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/web/routes/active/get-started/installation/+page.svelte

216 lines
6.5 KiB

<script lang="ts">
import CodeBlock from '../../_components/CodeBlock.svelte';
import Callout from '../../_components/Callout.svelte';
import PageNav from '../../_components/PageNav.svelte';
</script>
<svelte:head>
<title>Installation — Active</title>
</svelte:head>
<article class="article">
<header class="breadcrumbs">
<a href="/active">Get Started</a>
<span aria-hidden="true">/</span>
<span>Installation</span>
</header>
<h1>Installation</h1>
<p class="lead">
Active is a runtime that lives inside your SvelteKit project. It ships as a set of
path-aliased folders under <code>src/arts/*</code> rather than a published npm package, so
"installation" is really wiring the aliases and using the factories.
</p>
<h2>Prerequisites</h2>
<ul>
<li>SvelteKit <code>2.x</code> with Svelte <code>5.x</code> (runes mode).</li>
<li>TypeScript <code>5.4+</code> recommended for full inference.</li>
<li>A <code>Node 22+</code> runtime if you plan to use the server-authoritative engines (<code>$svrs/auth</code>, <code>$svrs/perm</code>, <code>$svrs/cache</code>).</li>
</ul>
<h2>Path aliases</h2>
<p>
The framework expects a fixed set of aliases, declared in <code>svelte.config.js</code>.
These match the folder layout under <code>src/</code> and let every artifact import its
peers without relative paths.
</p>
<CodeBlock
title="svelte.config.js"
lang="js"
code={`alias: {
'$active-app/services': 'src/arts/active-app/service-factories',
'$active-app/presets': 'src/arts/active-app/presets',
'$active-app': 'src/arts/active-app',
$adom: 'src/arts/adom',
$auth: 'src/arts/auth',
$bus: 'src/arts/bus',
$cache: 'src/arts/cache',
$connection: 'src/arts/connection',
$format: 'src/arts/format',
$http: 'src/arts/http',
$langs: 'src/arts/langs',
$logger: 'src/arts/logger',
$orca: 'src/arts/orca',
$perm: 'src/arts/perm',
$prefs: 'src/arts/prefs',
$session: 'src/arts/session',
$sium: 'src/arts/sium',
$storage: 'src/arts/storage',
$svrs: 'src/svrs',
$timer: 'src/arts/timer',
$libs: 'src/libs',
$locale: 'src/libs/locale',
$reactive: 'src/libs/reactive'
}`}
/>
<Callout variant="info" title="Why aliases?">
<p>
Aliases make every artifact import its peers as <code>$langs</code> /
<code>$logger</code>, regardless of where it lives. This keeps the boundary between layers
explicit and prevents accidental cross-imports.
</p>
</Callout>
<h2>Bundle policy</h2>
<p>
Active is designed to tree-shake. <code>package.json</code> declares only CSS and Svelte
files as side-effectful, and every barrel uses <strong>named re-exports</strong> instead of
<code>export *</code>:
</p>
<CodeBlock
title="package.json"
lang="json"
code={`{
"sideEffects": ["**/*.css", "**/*.svelte"]
}`}
/>
<p>
As a result, the minimum <code>createActiveApp(&#123;&#125;)</code> import has a measured budget
instead of a guess. <code>npm run test:bundle</code> builds a virtual Vite entry with OXC,
gzips the emitted JavaScript and fails above the configured budget.
</p>
<CodeBlock
title="Bundle smoke"
lang="sh"
code={`npm run test:bundle
# active bundle smoke: ~65 KB gzip by current baseline
ACTIVE_BUNDLE_GZIP_LIMIT_KB=70 npm run test:bundle`}
/>
<p>
The default budget is <code>70 KB gzip</code>. That is intentionally a smoke gate, not a
micro-benchmark: it protects the root runtime from accidental graph explosions while still
leaving room for the fixed App core.
</p>
<h2>First app</h2>
<p>
Create an <code>App</code> instance once at the root of your client tree. The most minimal
setup:
</p>
<CodeBlock
lang="ts"
title="src/lib/app.ts"
code={`import { createActiveApp } from '$active-app';
export const App = createActiveApp();
App.logger.info('app.boot', 'Active app ready');`}
/>
<p>
Even with no options, the fixed core is present: <code>App.logger</code>,
<code>App.bus</code>, <code>App.timers</code>, <code>App.orca</code> and
<code>App.prefs</code>. Feature modules are added explicitly under <code>services</code>.
</p>
<h2>Realistic setup</h2>
<p>For typed i18n, preferences, formatting, DOM projection and storage:</p>
<CodeBlock
lang="ts"
title="src/lib/app.ts"
code={`import { createActiveApp } from '$active-app';
import {
defineActiveLangs,
defineActiveFormat,
defineActiveDom,
defineActiveStorage
} from '$active-app/services';
import { createActivePrefsDomProjection } from '$prefs';
import { LogLevel, consoleTransport } from '$logger';
import { localAdapter } from '$storage';
import { schema } from './i18n/schema';
export const App = createActiveApp({
logger: { level: LogLevel.INFO, transports: [consoleTransport()] },
prefs: {
capabilities,
environment,
intent: { language: 'es', locale: 'es-ES' }
},
services: {
dom: defineActiveDom(),
langs: defineActiveLangs({ schema, defaultLocale: 'es', fallbackChain: ['en'] }),
format: defineActiveFormat(),
storage: defineActiveStorage({ adapter: localAdapter })
}
});
export const prefsProjection = createActivePrefsDomProjection({
prefs: App.prefs,
dom: App.dom
});`}
/>
<Callout variant="tip" title="Single-instance services">
<p>
<code>session</code>, <code>auth</code> and <code>perm</code> are declared as service
slots in <code>createActiveApp({`{ services: { session, auth, perm } }`})</code> via
<code>defineActiveSession()</code>, <code>defineActiveAuth()</code> and
<code>defineActivePerm()</code>. A duplicate slot is a JavaScript object-literal error,
so the schema makes "factory called twice" structurally impossible.
</p>
</Callout>
<h2>Verify</h2>
<p>
Open the playground at <a href="/test">/test</a> for an interactive page per artifact, or
jump straight to <a href="/test/ecosystem">/test/ecosystem</a> for the full integration
demo. After <code>npm run build</code>, use <code>npm run test:static</code> to verify that
the generated static docs, ecosystem test page and app assets exist.
</p>
<h2>Next</h2>
<p>
Read <a href="/active/get-started/ecosystem">Ecosystem</a> for the full layer map and
<a href="/active/get-started/composition">Composition</a> to understand how the artifacts
plug into each other, then drill into a module from the sidebar.
</p>
<PageNav />
</article>
<style>
.breadcrumbs {
display: flex;
align-items: center;
gap: 0.4rem;
font-size: 0.8125rem;
color: var(--c-fg-subtle);
margin-bottom: 1rem;
}
.breadcrumbs a {
color: var(--c-fg-muted);
}
</style>

Powered by TurnKey Linux.