1 poin oleh abcdkh1209 4 jam lalu | Belum ada komentar. | Bagikan ke WhatsApp

Halo. Saya membuat prewire, library DI build time untuk frontend TypeScript.

Alasan saya membuat library ini berasal dari struktur monorepo frontend yang saya kelola.

Frontend dari beberapa bisnis berbagi satu kode core/kit, dan saat ini aplikasi-aplikasi tersebut menggunakan Next.js. Ke depannya, saya ingin mencoba TanStack Router pada sebagian bisnis, tetapi saya juga tidak ingin membuat core bersama bergantung langsung pada next/navigation atau @tanstack/react-router.

Saya membutuhkan struktur di mana tiap bisnis bisa memilih implementasi yang berbeda, sementara core bersama tetap tidak perlu diubah.

Di prewire, kode bersama terlebih dahulu mendeklarasikan port dan token.

export interface RouterPort {  
  href(to: string): string  
  push(to: string): void  
}  
  
export const ROUTER = new InjectionToken<RouterPort>('router')  

Setiap aplikasi mengimplementasikan port ini dengan framework yang digunakannya.

export const tanstackRouter = injectable(  
  { logger: LOGGER },  
  ({ logger }): RouterPort => ({  
    href: (to) => to,  
    push: (to) => {  
      logger.info(`navigate → ${to}`)  
      throw redirect({ to })  
    },  
  }),  
  { provides: ROUTER },  
)  

Di sisi konsumen, termasuk kode bersama, cukup import path yang sama tanpa perlu tahu dari mana implementasinya berasal.

import { router } from '#prewire'  

prewire codegen menganalisis secara statis deklarasi injectable() dari aplikasi dan package bersama, lalu menghasilkan composition root TypeScript biasa sesuai urutan dependensi.

export const logger = consoleLoggerBinding.factory({})  
export const router = tanstackRouterBinding.factory({ logger })  

Tidak ada container runtime, reflect-metadata, atau decorator yang digunakan. Masalah seperti binding yang hilang, dependensi siklik, dan binding duplikat ditangani sebagai build error pada tahap code generation, bukan saat runtime. Kode yang dihasilkan bisa dibaca langsung, dan jika perlu juga bisa dipisahkan untuk dipakai sebagai composition root manual.

Agar implementasi package bersama tidak bisa ditimpa sembarangan oleh aplikasi, override juga tertutup secara default. Hanya binding yang ditandai default: true oleh kode bersama yang bisa diganti oleh aplikasi. Niatnya mirip dengan open di Kotlin.

Saya juga memisahkan sumbu environment. Dengan ini, root yang berbeda bisa dibuat berdasarkan kriteria apa pun yang diinginkan pengguna, seperti live/test, server/client, atau nama aplikasi bisnis. Misalnya, binding khusus server bukan sekadar tidak dijalankan pada root klien, tetapi import-nya sendiri tidak dimasukkan ke dalam kode yang dihasilkan.

Contoh di repositori saat ini berisi satu kit bersama yang dihubungkan secara berbeda oleh tiga aplikasi berikut.

  • Next.js
  • TanStack Start
  • React Router

Untuk integrasi build, tersedia unplugin untuk Vite·webpack·rspack dan withPrewire() untuk Next.js.

Namun, ini belum diterapkan pada kode produk nyata. Untuk saat ini, saya lebih dulu memvalidasi desainnya lewat library dan contoh terpisah, lalu merilisnya. Sekarang sudah dipublikasikan di npm sebagai 0.1.1, dan karena masih versi awal 0.x, API-nya bisa berubah.

Selain itu, jika hanya ada satu aplikasi, satu environment, dan jumlah binding-nya sedikit, alasan untuk memakai prewire tidak terlalu besar. Untuk proyek seperti itu, menulis satu file composition root secara manual akan lebih sederhana. Target utamanya adalah kasus ketika kode bersama yang sama perlu dihubungkan secara berbeda di beberapa aplikasi, environment, dan konfigurasi pengujian.

Saya sendiri lebih banyak mengembangkan backend, dan saat mengelola monorepo frontend saya menyelesaikan masalah ini dengan DI dan code generation build time. Karena itu, saya juga merasa pendekatan ini cukup bernuansa backend.

Saya penasaran bagaimana orang yang benar-benar fokus di frontend biasanya menyelesaikan masalah ketika beberapa aplikasi memakai core bersama tetapi implementasi khusus framework seperti router berbeda-beda. Apakah DI build time seperti prewire terlihat cocok, atau ada pendekatan yang lebih sederhana atau lebih akrab di ekosistem frontend? Saya ingin mendengar pendapat Anda.

GitHub: https://github.com/clroot/prewire
npm: https://www.npmjs.com/package/@prewire/core

Berlisensi MIT. Karena masih tahap awal, masukan kritis tentang desain dan API juga sangat saya sambut.

Belum ada komentar.

Belum ada komentar.