A frond from another repository

A frond can live in another repository, with its own team and release cycle. Your app still calls it. What has to reach your repository is its contract — its entities and operations — never its code.

Get the contract

Two commands, depending on how the other team shares it:

What it doesWhen
fougere syncasks the running frond for its card (rpc.discover) and writes its entities and facade into remotes/the frond is running — also the only way to use a frond written in another language
fougere build-frondcompiles its entities/ into a package you installthe other team publishes its contract as a dependency

Either way @fronds/<name> resolves, so your pages and handlers import the frond the same way as one of your own.

Call it

Give it its address, as for any frond in another process:

// fougere.config.ts
fronds: { billing: { remote: 'https://billing.internal' } },

The two processes must be able to reach each other, and the receiver must know who calls it: Deploy a split and Secure calls between processes.

Facts across repositories

Finding the listeners. When the other frond has an address in your fronds:, its card says which facts it accepts, and an announcement reaches it as a call — nothing more to write. A call keeps nothing, though: a listener that is down misses the fact. When that matters, or when the other side has no address you can call, put a carrier under the announcement — a queue or a broker of your own. Both sides meet on the fact's name, read off their own code:

const app = await createApp({
  root: import.meta.dirname,
  createContainer,
  onEmit: (fact, payload) => publishToYourBroker(fact, payload),   // out
});

// in — the same local dispatch, validation and links included
await app.deliver(fact, payload);
// what to subscribe to, read off your own signatures
app.listensTo();                                                   // ['postPublished']

Knowing the shape. A frond's card lists every fact its handlers announce, so fougere sync writes the fact's class rather than you copying its fields. Re-export it into one of your fronds, and an arriving fact is checked against the announcer's own declaration. When the shape changes, readers deploy before the sender: see Changing a fact.

A carrier has no address. An announcement and a listener name nobody, so a carrier can take a fact across. A Pipe<T> is called and answers, so it needs an address — it crosses processes, never a carrier. Emit<T, A> draws the same line: it needs answers back.

emit-multirepo runs two projects and one fact, and loses the first publication on purpose to show what a carrier buys.

Built with Fougere and Nuxt, hosted on GitHub Pages.