Låt oss prata om det.
Noder kan ladda en .NET assemblage och ropa på dess C-metoder utan att starta något annat process.
Båda runtimen körs i samma process.
Vi kommer att bygga båda riktningarna runt ett praktiskt exempel. :, med hjälp av vår De mest tydliga.Packning bibliotek. Noder ropar på C# för att hitta och reservera möten ; en M SK3 NET-applikation ropar sedan på den delade JavaScript formatteren genom ett inbyggdt nodMSC4 Vi mäter också latensiteten och minnesövertagningen mot en gRPC-bistol
Den sällskapliga prover inkluderar kompletta projekt och benchmark harness
Varför använda C# inuti en existerande nod-applikation
Vi har redan skrivit resourcen, -, packningsregler i ., NET och :, vilka anställda är kvalificerade för en tjänst. ,, när utrustningen behövs.,, och hur man sparar allt tillsammans. ., genom att ringa in den där biblioteket från Node-appn kan vi behålla reglerna på samma plats.
Vi kan ladda biblioteket till Node eller lägga det bakom en tjänst:
| Design | Vad noderanwendungen gör ♫ | ♫ Vad vi är ansvariga för ♫ | |||||||
|---|---|---|---|---|---|---|---|---|---|
Iprocessmodulen node-api-dotnet |
Loading . Net och inhemska beroenden inuti noderprocessen | ||||||||
| gRPC sidecar | skickar ett begäran till en separat | . | NET-tjänster | Hosting | МSK4 | övervakning och kommunikation med en annan process |
Att lagra biblioteket i Node för att undvika HTTP: s ringfärder/2 . En motordrivare kör motorn i en separat process, så den kan falla eller återstarta oberoende av webappletM SK3 Appen väntar på sin respons asynkronisktMSC4 och flera applikationsprocesser kan använda samma tjänstMST5
Vi ska mäta båda arrangemangen med samma C-implementation. Det låter oss jämföra angreppsöverskott och minnesförbrukning utan att ändra schemaalgoritmen.
Funktionen : antyder, previewM SK2 reserv
Alice vill ha geler, . Beth vill ha pedicure,. De vill börja tillsammans,. Varje möte behöver en kvalificerad tekniker och den lämpliga stationen.
Frågan går genom det existerande bakprogramet:
sequenceDiagram
participant Browser as Existing calendar UI
participant Node as Existing Node backend
participant Engine as C# packing engine
Browser->>Node: Find appointments within this window
Node->>Engine: FindTogether(window, services)
Engine-->>Node: Candidate, assignments and revision
Node-->>Browser: Suggested calendar events
Browser->>Node: Accept this candidate
Node->>Engine: TryHold(candidate, command ID)
Engine-->>Node: Hold accepted or rejected
Node-->>Browser: Show held appointments or refresh suggestions
Ett förslag är förenklat.. Någon kan ta plats medan användaren tittar på kalendern.
“AutoM SK1planering” betyder att hitta en genomförbar gemensam tjänstgörelse under deklarerade begränsningar . Det här exemplet ordnar inte upp hela dagen eller ger ett globalt optimalt plan
kör arbetsexemplet
Använd .NET | 10 | och nod |22. | Håll mostlylucid.packing och mostlylucidweb som syskonkontroller, och sedan springa från mostlylucidweb/samples/NodePacking:
npm ci
npm run build
npm run booking
Ni borde se:
alice: gels with sarah
beth: pedicure with anna
Both appointments confirmed.
Den exempel README har klona kommandor och instruktioner för att använda en annan checkout-position. Sampleset bygger packningsversionen från källan
Sampleset använder 3 juni 2030, en fixerad klocka och en in-memory-databank, så att varje lopp börjar med samma tillgänglighet.
1. Beskriv de resurser som programmeraren måste respektera
Ett tomt kalenderslot säger inte till oss om en kvalificerad tekniker och rätt utrustning är tillgänglig.
Alices appointment med gelbeläggning tar upp dessa resurser
| Avset från början | Etappe | Bevarade resurser |
|---|---|---|
| 0–15 minuter | förbereda | Sarah och manicure stationen МSK4 |
| 15–35 minuter | torr | Manikürstation och lampe МSK4 |
| 35–45 minuter | avsluta | Sarah och manicure stationen M |
| 45–55 minuter | Reset | Manikurstationen M |
Till exempel , i det här stadiet säger att lampan behövs från minuten 15 till minuten
new ServiceStage(
"dry",
TimeSpan.FromMinutes(15),
TimeSpan.FromMinutes(20),
["station", "lamp"])
station och lamp är rollnamen . Servicedefinitionen säger vilka förmågor som kvalificerar en resurs för varje roll. Motorn tillhandahåller resurser till dessa roller
Sarah är inte upptagna under torrningen. Hon behövs igen för att färdigställa. Stationen är fortfarande upptagen efter Alice ' kunderna M SK3 mötesbesöket slutar eftersom det behöver ställas om . En sökning nära slutet av tiden måste passa in i den ställningen också MSC5
Den kompletta salondefinition deklarerar Sarah, AnnaM SK1 två stationen , en lampe , tjänster och ett femminuterstimmarsnät M SK5 Du kan byta dessa deklarationer för att pröva olika personal- eller utrustningsbegränsningar MSC6
2. Fråga motorn CM SK1 om ett gemensamt möte
I C#, kombinerar ett kalender med en definition och en reservationsbutik
var definition = SalonDefinition.Create();
using var store = new SqliteCalendarStore(":memory:", definition);
var calendar = Pack.Calendar(definition, store);
Sampeln's exporterade klass tillhandahåller också den fixera klocken . För att hitta en starttid för båda kunderna
var result = calendar.FindTogether(
from, to,
[new BookingRequirements("gels", "alice"),
new BookingRequirements("pedicure", "beth")],
limit: 1);
Här from och to är DateTimeOffset värden. Resultatet består av en kandidat vars nominationer delar starttid , med resursfördelar för varje tjänst M SK2 sökfenon gränsar hela resursavtrycket , inklusive återställingsstader MSC4
limit: 1 begär en återvänd match. Prüfa CandidatesComplete innan man tolkar ett tomt resultat Version identifierar reservationsvalet som används för sökningen.
bryggan håller CalendarMatch i C#. JavaScript får dess ID och de nominationsfällor som behövs för att kunna se fram. När användaren accepterar,, ser bryggan upp den som matchar och sparar dess resurser. Browsern skickar inte fram resourcesbehovet
3. Exposera den operationen till noden
Vi använder Microsoft.JavaScript.NodeApi och dess generator, ,, kopplad till 0.9.36. tillämpar [JSExport] till vår Salon klass gör sina offentliga metoder tillgängliga som nodermodul. skapad moduls arbetsflöde.
Lade upp den genererade modulen från dess montageväg:
import { fileURLToPath } from 'node:url';
import dotnet from 'node-api-dotnet/net10.0';
const assembly = fileURLToPath(new URL(
'./PackingBridge/bin/Release/net10.0/PackingBridge.dll', import.meta.url
));
const { Salon } = dotnet.require(assembly);
PackingBridge.dll är en skött .NET assemblage. Paketet hostar .NET inuti Noden och laddar dess exporterade metoderM SK3 Uppmanade gränser mellan JavaScript och | . | NET i den processen
Använda dotnet.require() för det exporterade modulet. Det separata dotnet.load() API är till för att ladda godtyckliga assembler och få tillgång till deras offentliga typer genom .NET Namespacer Referens för JavaScript beskriver båda.
För den prövade npm-versionen, är importen node-api-dotnet/net10.0. Ett äldre dokumentationsexempla innefattar .js, som misslyckas med detta paket
Släng inskrivna objekt genom gränsen
BuchungsAPIn återvänder C# objekt direkt
public SearchOffer FindTogether(SearchWindow window)
begäran är en liten struktur med namn på fält:
public struct SearchWindow
{
public string Start { get; set; }
public string End { get; set; }
}
På nodersidan, accepterar exporterad metod ett objekt:
const session = new Salon(':memory:');
const offer = session.findTogether({
start: '2030-06-03T10:00:00Z',
end: '2030-06-03T12:00:00Z'
});
console.log(offer.appointments[0].technician);
Generatoren producerar deklarationer för SearchWindow, SearchOffer, AppointmentView och ReservationResult. Deras metoddeklaration är nu
findTogether(window: SearchWindow): SearchOffer;
Det finns ingen serialiserad JSON-sträng mellan denna sändning och metoden C# outcome, candidatesComplete, candidateId och appointments. Håller och bekräftar också återskapar inskrivna resultat kontraktsfilar definierar exporterade fält. Datums fält förblir ISO-strängar så att kalendern kan konsumera dem direkt
De TypeScript-deklarationerna beskriver API: t i kompileringsögonblicket.
Kurser och strukturer har olika kostnader
Noder API för .NET kopierar strukturer efter värde. Att läsa ut de resulterande JS-eigenheterna låter inte ' kalla en | . | NET-behållare ♫ . ♫ Vi använder strukturer för begäran och små Buchungssvarningar ♫
Det nesterade sökresultatet använder exporterade kategorier. En klass exponeras genom en wrapper runt det skötta objektet, så att läsa en egenskap korsar sig till .NETM SK3 Att ta bort JSON inte removerar de där samtalenMSC5 radens omvandling eller fördelningar att samla ihop dokumentation förklarar livstid och omvandlingsregler.
Jag försökte göra inspelat sökresultatet till en struktur också, men 0.9.36 generatorn lyckades inte bygga upp dess ställelse- skiffer omvandling. Klassenresultatet som visas här bygger och passerar testerna . Detta är en begränsning av den testade föreställningen och kontraktformaden M SK3 inte ett påstående att strukturresultat i allmänhet inte stödjers
Lees resultatet en gång för webapplikationen
Den JavaScript-wrapper bevarar de bekväma två argument API: n som användes under ett ögonblicksbild av de återfällda egenskaperna in i vanliga JS-data . Det läser varje fält en gång, inklusive varje nominationsfält, utan JSON.stringify eller JSON.parse.
Snapshotet undviker upprepade managed getter sändningar eftersom applikationen bygger kalendrar händelser. Det ger HTTP-skivan uppंकbara datafält för att serialisera ; Att skicka en managed wrapper direkt kan utelämna egenskaper som exponeras genom prototypen. Vi testar att snapshotet överlever en vanlig HTTPM SK3style JSON rund resaMSC4 JSON vid webbläsarens gräns är separerad från JSON mellan noder och Mska5NETMske6
Declarationerna i wrappern' förbehåller genererade C # kontraktstyper npm run typecheck för att kontrollera en TypeScript-konsument, inklusive förväntade fel på ett felaktigt parametrtyp och en okänd resultat- egenskap ValueType bas för strukturer, så den här checken använder skipLibCheck för beroende deklarationer. konsumentfältet och argumenten är fortfarande kontrollerade ; det är inte en ren kontroll på generatorn
4. Hitta en förslag från Nodes baksida
Med lådan laddad, ser applikationskod ut som den här
const salon = createSalon(':memory:');
const offer = salon.findTogether(
'2030-06-03T10:00:00Z',
'2030-06-03T12:00:00Z'
);
if (!offer.candidateId) {
throw new Error(`No joint appointment: ${offer.outcome}`);
}
Den [from, to] värden kommer från användaren' det ausgewählta vensteret i den existerande appen . konstruktionen har Alice' och BethM SK3 servicebehovet byggt in i bron ; applikationsAPI skulle acceptera validerad service
Angebotet består av två affischer för att visas: Alice ' geler med Sarah M SK2 och Beth ' pedicure med Anna MSC4 båda från 10:00 UTC MST6 Det bär också kandidaten ID MSV7 revisions- och komplettitetsflaggen M SV8 När man får reda på att programmet inte har ändrat kapaciteten
Datum överskrider gränsen som ISO-timmar med avvikelser. Håll det budskapet oföränderligt genom baksidan , och låter kalendern i konfigurerad tidszon handlera displayen
5. Dodaj föreslagna händelser till den existerande kalendern
Vår Kalenderadapter kartlägger valprojektionerna till händelseobjekt
export function toCalendarEvents(offer) {
return (offer.appointments ?? []).map(appointment => ({
id: `${offer.candidateId}/${appointment.clientId}`,
title: `${appointment.clientId}: ${appointment.serviceId} (${appointment.technician})`,
start: appointment.start,
end: appointment.end,
editable: false,
extendedProps: { candidateId: offer.candidateId, state: 'suggested' }
}));
}
Ge tillbaka de händelserna tillsammans med programmet från din nuvarande arrangemangs slutpunkt. För en FullCalendar
const preview = calendar.addEventSource(suggestion.events);
Det här är full kalender, ' och dokumenterad händelsefällor, lisädes genom event- källa API. Sampleset testar händelsernas kartläggning . Du' kommer att behöva koppla din avvägningspunkt till den existerande kalenderns gränssnitt
De föreslagna händelserna är inte redigerbara eftersom att dra en självständigt skulle kunna bryta den gemensama Buchungen. preview.remove() och fråga om ett nytt Angebot.
Den markerade möten slutar när kundens service slutar' . Motoren sparar också städtid, så nästa Buchung måste komma från en ny tillgänglighetskontroll även om skärmen verkar ha ett hål
Konnekt till autentiska Buchungsdata
Sampeln äger sin SQLite-reserveringssituation. För att integrera den med en existerande app , karta över appn, ' personalen, M SK3 tjänster, , tillgänglighet och aktiva engagemang i maskinen M SK5 bara kalendereventen vann ' inte tillgångskvalifikationer,, utrustningskapacitet eller återställningsbehov,.
Sök- och bokande måste använda samma källa till beställningsdata. Om du skriver till den gamla Buchungsdatabasen och en separat paketdatabas oberoende av dig , ett misslyckat skrivande kan låta dem inte hålla med om det . Välj vilken komponent som äger beräkningar och hur den andra läser eller uppdaterar dem innan man lägger in schemat i appn M SK3
6. Håll kandidaten, ,, och bekräfta den
När användaren accepterar föreställningen
const commandId = randomUUID();
const hold = salon.tryHold(offer.candidateId, commandId);
if (!hold.success) throw new Error(hold.reason);
const confirmation = salon.confirm(hold.reservationId, randomUUID());
if (!confirmation.success) throw new Error(confirmation.reason);
randomUUID kommer från node:crypto. En kommando ID identifierar en operation , så att en repetition av samma operation måste återanvända dess ID
Bridgen som utgör C: n är #.
calendar.TryHold(commandId, "alice", match, TimeSpan.FromMinutes(5));
match är den förvarade maskinens resultat. SQLite-butiken förvärvar de länkade kraven i en affär
Vårt korta exempel bekräftar det omedelbart. En applikation skulle istället kunna behålla hållet medan användaren completerar en överprüfung eller betalande steg , och sedan bekräfta eller avbryta den enligt den strömmen
I längre demo, två anslutningar söker samma affär innan de båda sparar något . utgången visar vad som händer när båda försöker använda resultatet
First hold: true
Same command returns same reservation: true
Competing stale offer accepted: false
Sarah free during drying: true
Sarah free during finishing: false
Confirmed: true
Detta kontrollerar ett föråldrade förslag med hjälp av en upprepad sekvens av samtalen. Samma processer skulle behöva en separat stresstest
Bestämningen antar att Alice kan boka för Beth Salon instance: omfattningen av den instancen till ett Buchungsverk
Gör det att JSONs radning gör samtalet snabbare?
Det tar bort serialiseringen , men ersättningen kostar också. För att mäta dem Benchmark harness nu jämför tre vägar:
- Tiktade objekt i processen, inklusive att läsa varje återvända fält i JS-snapshot.
- JSON i processen - , inklusive serialisering och JavaScript parsing
- Ett gRPC-bilar, som bär den JSON-responsen i ett protobuf- meddelande.
Alla tre ropar på samma C# sök och bygger samma resultatmodell FindTogetherJson metod är kvar endast för jämförelsen och bilaradaptern. ApplikationenM SK1 använder FindTogether och tryckta resultat.
Benchmarken läser hela resultatet på varje väg. Timing bara skapandet av en skött objektompackare skulle lämna ut arbetet som kalenderappn måste göra senare. Knyckseln kontrollerar den återvända kandidaten och uppgifterna över alla tre vägar , och varje mätt sök utför noggrannhetenskontroller
Latens och sequentiell genomspetsning
mätt på en Apple M5, macOS ARM64, 32 GiB RAMM SK3 Nod v22.15.0 och .NET SDK 10.0.201. Avgasbilen använder Grpc.AspNetCore 2.85.0; som Nodeclienten använder @grpc/grpc-js 1.14.7. Båda | . | NET-händer använder arbetsstation GC
Var och en av tre nya processtestar värmer upp varje aktivitet med 200 sändningar | , | och mäter sedan ♫ 1,500 sändningarna vid samtida sändning | 1 |. | De tre moderna roterar genom loppet | МSK5 | Varje tabelinskrywing är den medianen i den statistiken över testerna | p50 är ett mellantal av ringer latens p95 är den tid i vilken 95% av en testinspelning 's samtalen avslutades
| jobb per sändning | väg | p50 | p\95 | Sekundära sändningar | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Echo a 1 KiB-fält | 2 | Typobjekt | 3 | Snapshot av JS | 4 | 5 | μs | 6 | 7 | mm | 8 | 9 | 10 | |
| Echo a 1 KiB-fält ♫ ♫ | ♫ JSON interop ♫ | |||||||||||||
| Echo a 1 KiB-fält ♫ ♫ | ♫ gRPC ♫ | |||||||||||||
| Hitta den gemensama inställningen | Typerade objekt | МSK2 | JS-snapshot | |||||||||||
| Hitta den gemensama anställningen | JSON interop ♫ ♫ | ♫ | ||||||||||||
| Hitta den gemensama anställningen | gRPC ♫ ♫ + ♫ JSON-respons ♫ |
Det skrivna söket var långsammare vid p50 i den här konstruktionen Det tog ungefär 621 μsM SK1 jämfört med 575μs genom JSON och 718 μ s genom gRPC. I parade testerMSC5 när man läste utskrivet resultat, så kom det ungefär ♫ 33–87 μS till över JSON-versionenMska7 Det utskrivna pMske8 var lägre i den sammanlagda tabelnMsko9 så mätningarna inte stödjer ett överlagde påstående att antingen i -, eller så vinner processen vid varje procentil
Klassbeslagare och den explicita JS-snapshot förklarar varför serialiseringen behöver undvikas' inte är en acceleration. Vi läser fält genom interop-layern och skapar JS objekt för applikationen . För denna lilla uppdragningM SK3 concurrar JSON-encodern / paret som analyserar bra med det arbetetMska5 En annan uppdragingMske6 en annan DTO-form eller förbättrad värdeM Ska7 typmarshalling skulle kunna ändra resultatet Mska8 dessa behöver sina egna mätningar M Ska9
Echokontrollen passerar ett 1 KiB textfält genom varje väg . dess inskrivna version använder en värdestruktur, sen läser den återvända fältetM SK3 Dess JSON-version passerar och tolkar en JSON stringMska4 Även härM Ska5 direkt marshalling har jobb att göraM ska6 den läser och kopierar objektfälten Mska7 Att ta bort JSON ensamma gör det inte M Ska8 gör gränsen fria M ska9
Timmaarens respons är 495 byter när representerad som JSON.
Vad är gRPC överhuvudtaget?
gRPC-tjänsterna ropar FindTogetherJson över en återanvändad enkeltext HTTP/2 koppling på loopback TCP. Clienten följer kanal-användbar vägledning, så att kopplingen bildas innan mätda samtalen sker. Det finns ingen TLSM SK2 proxy eller fjärran nätverk i detta test
I parade tester, var dess sökpM SK1 ungefär 119–282 μs högre än JSON interop och 32–221 μ s högre än den skrivna vägenMSC4 Det innefattar protobufbehandlingarMska5 HTTPMske6 trådens scheduling och JavaScripts återkopplingM Ska7 Föregång handlingar Mska8 Ett fullt skrivt Protobuf försvar skulle ha olika serialiseringskostnaderMskan9 Dessa siffror beskriver adapteret som byggdes härMskar10 snarare än ett fixet överskott för gRPCMsker11
Skillnaderna är små för en enda kalender.-knappklicken.
Det här var en utveckling- maskin som kördes med naturliga skräphantering och annan systemactivitet . samtalen/ kolumnen rapporterar sequentiell strömförbrukning vid samspelning ett . Serverskapacitet under samma belastning M SK4 reservskriver och skriver emotstånd behöver separata tester MSC5
minne: räkna hela arrangemanget
RSS är den inhemska minnen som rapporteras för en process.
| Arrangement | Initialiserad RSS | RSS efter arbetsbelan | |||
|---|---|---|---|---|---|
| Tiktade objekt ♫ + ♫ JS-snapshot ♫ | ♫ | ||||
| JSON interop | 107.3 MiB M | 124.9 | MiB | ||
| gRPC |
Det här är medianskapbilder efter den första korrekta sökningen och efter uppvärmningarna och tidiga arbetslader.. Ingen tvångsmässig V-kollektivation utförs.
Den skrivna vägen minskade inte RSS jämfört med JSON här. Att ta bort textbuffer kan kompenseras genom skötta omloppsmaskiner , kopierade objekt och deras livslängder. En RSS-snapshot kan inte isolera fördelningen av serialiseringskostnader
För gRPC, lägger tabellen till nodesclienten's RSS till bobåten 's arbetslådaM SK3 Att bara titta på klientet skulle gömma större delen av arrangemanget . Uppskattad RSS kan räkna ut delade sidorna mer än en gång MSC5 och samblandningstimmar påverkar bevarade minnen M SK6 De är inte unika fysiska data,
De råresultaten bevarar varje process, ', mätningarna separat.., behållare, ,, GC-inställningar, M SK3, last, Mska4, påladung och en kantbil som delar sig av flera noderprocesser kan ändra jämförelsen.
Synkroniserade samtal blockerar fortfarande Node's händelseloop
Båda iprocesssökningsmetoderna körs synkroniserat på den som ropar på nodertråden... Att ge tillbaka ett skrivet objekt ändrar inte var söket körs. .. gRPC-clienten väntar på ett svar medan arbetet sker i den andra processen.
Grejen programmerar en 10 ms timer , sedan utsläpper | 100 | sökningar |. | Zusätzliche timerverzögerung var ungefär 31–53 ms för inskrivna objekt, 30–33 ms för JSON interop, och 0–0.9 ms genom gRPC. Bresten tar bort de återlämnade datan , inklusive det skrivna ögonblicksbildet eller JSON-testet M SK2 men utelämnar latens-loopen ' s per MSC4 samtalets påståenden och tidning MST5
Den sprickningen skulle också skjuta upp orelaterade återkopplingar på samma nodersträng.
Reproduera mätningarna
npm run build:bench
npm run bench
npm run bench:summary
Lämparen startar och stannar med sin egen loopback-bilar.,, använder färska klienter, ,, och kontrollerar resultatets jämlikhet. råresultat including trial values, environment details and hashes of the measured assemblies BENCH_TRIALS och BENCH_ITERATIONS konfigurera loppet.
De här mätningarna täcker sökningar och en kontrollensändning.
Den bakåtgående riktningen: C# kallar vår JavaScript-modul
Den existerande nodesappen har också JavaScript som vi kanske vill ringa från .NET. Båda provapplikationerna använder samma Buchungsformatorn . CM SK3 applikationen laddar den genom en inbyggd nodesruntime och passerar objekt direkt
var offer = salon.FindTogether(new SearchWindow
{
Start = "2030-06-03T10:00:00Z",
End = "2030-06-03T12:00:00Z"
});
var text = runtime.Run(() =>
new BookingFormatter(runtime.Import(modulePath)).Format(offer));
modulePath pekar på format-booking.cjs. Den BookingFormatter-adaptator skapar JSObject och JSArray värden från det skrivna förslaget, så väcker den modulen's format funktionen genom Node-API. Den här omvända adaptern använder explicit objektkonstruktion snarare än den genererade modulen
JavaScript formatter läser offer.appointments direkt och återvänder:
format-booking.cjs: 11:00 London: alice: gels with sarah; beth: pedicure with anna
samtalet kör inuti runtime.Run, på JS-omgivningstråden . Alla JS objekt finns kvar i detta återkopplingsmönster Format(SearchOffer) handtekening, medan dess implementering hanterar de ursprungliga JS-värdena .
kör den med npm run reverse. Den att bygga in ett program hanterar plattformskapande och infödda-vägsselection. den använder Microsoft.JavaScript.LibNode 20.1800.203, parningen som testats här med Node API 0.9.36.
Den här gången, ,, är NET-applikationen som äger processen och har värden embedding support förblir experimentell, med en version libnode binär betyder inte att ' nödvändigtvis levererar denna wrapper, ', inbäddade exporter och .
Det omvända exemplet ser till att objekt passerar och formaterar.
Att paketera integreringen
Den projektfile möjliggör CopyLocalLockFileAssemblies så att de skötta beroendena följer DLL. fasad löser också SQLite's inhemska bibliotek explicitt. De detaljerna var nödvändiga i den testade nodeshändern native- laddande dokumentation förklarar mekanismen.
En inhemsk AOT .node addon skulle kunna ta bort den separat installerade .NET runtimeanforderungen. MicrosoftM SK2s C# Dev Kit exempel visar att angreppet är möjligt. Den skrivna Buchungspfad avoiderar JSON serialiseringen , men paketabhängighetens grafen, skapade bindningar och SQLite-tillgångar behöver fortfarande separat AOT-validation . Den här instruktionen publicerar inte eller mäter varianten
I' startar med den genererade modulen för denna kalenderapp om dess sökningar är tillräckligt korta för att fungera på nodertrådet och jag kan paketera de ursprungliga beroendena med appn . I' använder en kantbil om jag behöver process isolering , oberoende uppgraderingar eller en maskin som delar med sig av flera klienter
Båda funktionella demonstreringar, reservkontroller och benchmarks utfördes på macOS ARM64. Kalendern - händelseförspelning är undersöktM SK3 men ingen komplett webblader-applikation är tillgänglig