Cookbook
Практические паттерны для проектов на @azure-net/kit.
Алиасы контекстов
Держите алиасы контекстов явно в azure-net.config.ts, чтобы CLI мог строго проверять границы.
export default {
packageManager: 'pnpm',
coreAlias: '$core',
sharedAlias: '$sharedKernel',
contexts: [
{ name: 'public', alias: '$public' },
{ name: 'admin', alias: '$admin' },
{ name: 'shared-kernel', alias: '$sharedKernel' }
]
};sharedAlias используйте только для настоящего общего контекста. Другие контексты могут импортировать его, но сам shared-контекст не должен импортировать другие app-контексты.
Program entrypoint
Всю lifecycle-логику SvelteKit держите в src/program.ts. Не создавайте hooks.server.ts и hooks.client.ts; AzureNetPlugin подключает их виртуально.
import { createApp } from '@azure-net/kit';
import { TranslationManager } from '$core/translation';
export const { register, Container } = createApp((app) =>
app
.useServer(async ({ resolve, event, useMiddlewares }) => {
await useMiddlewares([
({ to, next }) => {
if (to.pathname.startsWith('/private')) {
return next('/login', 303);
}
return next();
}
]);
const { preloadTranslation, applyHtmlLocaleAttr } = TranslationManager();
await preloadTranslation();
return resolve(event, {
transformPageChunk: ({ html }) => applyHtmlLocaleAttr(html)
});
})
.useClient(({ useMiddlewares }) => {
useMiddlewares([
({ next }) => {
next();
}
]);
})
.dependencies({
translationManager: () => TranslationManager()
})
);Infrastructure provider
Datasource и репозитории живут в infrastructure layer. Провайдер владеет конкретными реализациями.
import { createBoundaryProvider } from '@azure-net/kit';
import { createHttpServiceInstance } from '@azure-net/kit/infra';
import { ApiDatasource } from '$core/datasource';
import { ContentRepository } from '$public/layers/infrastructure/http/repositories';
export const InfrastructureProvider = createBoundaryProvider('PublicInfrastructureProvider', {
register: () => ({
ContentRepository: () =>
new ContentRepository(
new ApiDatasource({
http: createHttpServiceInstance({
prefixUrl: '/api'
})
})
)
})
});Application provider
Application provider зависит от infrastructure provider своего же контекста и наружу отдает use-cases.
import { createBoundaryProvider } from '@azure-net/kit';
import { InfrastructureProvider } from '$public/layers/infrastructure/providers';
import { ContentUseCases } from '$public/layers/application/use-cases';
export const ApplicationProvider = createBoundaryProvider('PublicApplicationProvider', {
dependsOn: {
InfrastructureProvider
},
register: ({ InfrastructureProvider }) => ({
ContentUseCases: () => new ContentUseCases(InfrastructureProvider.ContentRepository)
})
});Presenter
Презентеры остаются в presentation layer и ходят только в application use-cases. Запросы обычно становятся async resource, мутации - async action.
import { AppPresenter } from '$core/presenter';
import { ApplicationProvider } from '$public/layers/application/providers';
export const ContentPresenter = AppPresenter('PublicContentPresenter', ({ createAsyncResource }) => {
const { ContentUseCases } = ApplicationProvider();
const collection = () => createAsyncResource(() => ContentUseCases.collection());
return { collection };
});Генерация модуля
Для CRUD-like модуля удобнее начать с пресета:
azure-net generate module-presetCLI создаст доменные контракты, репозиторий, use-cases, затем подождет, пока вы вручную свяжете infrastructure/application providers. После этого он сгенерирует presenter.
Перед коммитом generated-кода прогоняйте внутренние проверки:
azure-net check internalДля полного локального гейта:
azure-net check project