<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anthony Viard</title>
    <description>The latest articles on DEV Community by Anthony Viard (@avdev4j).</description>
    <link>https://dev.to/avdev4j</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F683599%2Ff459ca31-7fd6-4de1-a351-2061ccc2895a.png</url>
      <title>DEV Community: Anthony Viard</title>
      <link>https://dev.to/avdev4j</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/avdev4j"/>
    <language>en</language>
    <item>
      <title>Upgrading OtakuShelf to JHipster 9.1.0</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Wed, 27 May 2026 21:43:08 +0000</pubDate>
      <link>https://dev.to/avdev4j/44-upgrading-otakushelf-to-jhipster-910-242</link>
      <guid>https://dev.to/avdev4j/44-upgrading-otakushelf-to-jhipster-910-242</guid>
      <description>&lt;p&gt;JHipster 9.1.0 just dropped. For years, that sentence put a specific knot in Sam's stomach — version bumps meant a git-merge adventure, surprise conflicts, and the nagging fear of a file you'd customized getting quietly overwritten. OtakuShelf is on 9.0.0 and Sam actually likes it the way it is. So the real question isn't "how do I upgrade," it's "&lt;em&gt;should&lt;/em&gt; I, and what will it cost me?" The agent can answer both before a single file changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, how big is this really?
&lt;/h2&gt;

&lt;p&gt;Sam starts by scoping it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How risky is upgrading &lt;code&gt;/Users/sam/projects/otakushelf&lt;/code&gt; to JHipster 9.1.0?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;upgrade_advisor&lt;/code&gt; tool reads OtakuShelf's &lt;code&gt;.yo-rc.json&lt;/code&gt; and entity configs and reports back the shape of the jump:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;current &lt;strong&gt;9.0.0 → 9.1.0&lt;/strong&gt;, a &lt;strong&gt;minor&lt;/strong&gt; bump;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;risk: low&lt;/strong&gt; — no blueprints, a plain monolith, a handful of entities;&lt;/li&gt;
&lt;li&gt;a couple of project-specific notes (nothing alarming here) and a short checklist;&lt;/li&gt;
&lt;li&gt;links to the &lt;strong&gt;9.1.0 release notes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing Sam appreciates: the advisor doesn't &lt;em&gt;invent&lt;/em&gt; a list of breaking changes. A minor release shouldn't have many, but for the authoritative word it points Sam at the release notes rather than bluffing. It gives the facts and the scope; the specifics live where they actually live. For a minor, low-risk bump, the verdict is "go for it" — but Sam still wants to see the damage first.&lt;/p&gt;

&lt;h2&gt;
  
  
  The preview that doesn't touch a thing
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Show me what upgrading OtakuShelf to 9.1.0 would change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the one Sam wishes had existed years ago. &lt;code&gt;preview_upgrade&lt;/code&gt; regenerates OtakuShelf's own model in an isolated temp copy &lt;strong&gt;using generator 9.1.0&lt;/strong&gt; — fetched on the fly via &lt;code&gt;npx generator-jhipster@9.1.0&lt;/code&gt;, so Sam doesn't even have to install it globally first — and diffs the result against the current project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Upgrade preview → generator-jhipster@9.1.0:
  +1 added  -0 removed  ~14 modified
Added (1): ...
Modified (14): build dependency bumps, a few Vue components, Liquibase config, ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OtakuShelf itself is &lt;strong&gt;never touched&lt;/strong&gt; — it's a diff against a throwaway regeneration. And there's an honest caveat the tool states plainly: that &lt;code&gt;modified&lt;/code&gt; list mixes two things — changes the new generator makes &lt;em&gt;and&lt;/em&gt; files Sam has customized. Telling them apart is the real work of any JHipster upgrade. The difference now is that Sam sees the whole list &lt;strong&gt;up front&lt;/strong&gt;, on a calm afternoon, instead of discovering it mid-merge at 11pm.&lt;/p&gt;

&lt;p&gt;Fourteen modified files, mostly dependency bumps and regenerated boilerplate, nothing touching Sam's hand-edited Franchise view. This is a Tuesday, not an adventure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying it Sam's way
&lt;/h2&gt;

&lt;p&gt;Notice what the MCP did &lt;em&gt;not&lt;/em&gt; do: it didn't run the upgrade. The official &lt;code&gt;jhipster upgrade&lt;/code&gt; is a git-based merge, and this server stays deliberately out of your git — so it previews instead of merging. With the diff in hand, Sam drives the actual change through a normal workflow: commit the current state, run the upgrade (the agent can kick off &lt;code&gt;jhipster upgrade&lt;/code&gt; through the escape hatch, or Sam runs it by hand), and resolve the handful of spots the preview already flagged. Because Sam committed first and knew the blast radius in advance, the merge is a quick, confident review rather than a leap of faith.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;./mvnw verify&lt;/code&gt; and an &lt;code&gt;npm test&lt;/code&gt; later (the MCP told Sam those commands back in part 1, remember), OtakuShelf is happily running on 9.1.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Sam got out of the experiment
&lt;/h2&gt;

&lt;p&gt;Four sittings ago, OtakuShelf was an empty folder and a vague idea, and Sam was skeptical about letting an AI near a generator. Now there's a paginated, DTO-backed catalog of manga and anime — scaffolded, grown, polished, and version-bumped — and at no point did the agent's involvement mean &lt;em&gt;less&lt;/em&gt; control. The pattern that emerged was simple and stuck:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;describe&lt;/strong&gt; the change in plain language;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;validate and dry-run&lt;/strong&gt; before touching the project — for free, because the MCP previews by isolation, not by trusting a flag that lies;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;apply&lt;/strong&gt;, occasionally with a &lt;strong&gt;backup&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;and let the agent &lt;strong&gt;read the real project&lt;/strong&gt; so its edits stay surgical.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The MCP didn't replace Sam's JHipster judgment. It deleted the friction around it — the JDL typing, the CLI prompts, the upgrade dread — and left the decisions where they belong.&lt;/p&gt;

&lt;p&gt;That's the shelf built. Time to actually add some manga to it. 📚&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want the precise arguments and edge cases behind any of this? The story motivates; the &lt;a href="https://github.com/avdev4j/jhipster-mcp/blob/main/docs/README.md" rel="noopener noreferrer"&gt;docs&lt;/a&gt; specify — start with the &lt;a href="https://github.com/avdev4j/jhipster-mcp/blob/main/docs/04-tools.md" rel="noopener noreferrer"&gt;tools reference&lt;/a&gt;. And the server itself: &lt;a href="https://www.npmjs.com/package/jhipster-mcp" rel="noopener noreferrer"&gt;jhipster-mcp on npm&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jhipster</category>
      <category>ai</category>
      <category>java</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Polishing the catalog (and reading the agent's receipts)</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Wed, 27 May 2026 21:42:51 +0000</pubDate>
      <link>https://dev.to/avdev4j/polishing-the-catalog-and-reading-the-agents-receipts-2c0g</link>
      <guid>https://dev.to/avdev4j/polishing-the-catalog-and-reading-the-agents-receipts-2c0g</guid>
      <description>&lt;p&gt;OtakuShelf models everything now, but it's a prototype with prototype habits: the anime entities Sam added last week aren't paginated, there are no DTOs anywhere, and — Sam just noticed while adding &lt;em&gt;Attack on Titan&lt;/em&gt; — there's nowhere to record that a franchise comes from Japan vs. Korea vs. wherever. Time for a polish pass. And since OtakuShelf is a real project Sam has hand-tweaked, this is also where a safety net earns its keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it look production-shaped
&lt;/h2&gt;

&lt;p&gt;First, consistency. Sam wants pagination on the new anime entities too, and a DTO + service layer across the board so the API isn't exposing entities directly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In &lt;code&gt;/Users/sam/projects/otakushelf&lt;/code&gt;, paginate every entity, and put all of them behind MapStruct DTOs and a service layer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent reaches for &lt;code&gt;set_option&lt;/code&gt;, the tool for exactly these JDL option lines, and applies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;paginate * with pagination
dto * with mapstruct
service * with serviceClass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same &lt;code&gt;dryRun&lt;/code&gt; habit from last time — Sam previews, sees it's just regenerating resource/service layers and Vue services, and applies. Nothing dramatic, which is the point: option changes should be boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  The field Sam forgot
&lt;/h2&gt;

&lt;p&gt;Now the missing field. This is the moment that makes people nervous about regenerators — Sam has hand-edited the &lt;code&gt;Franchise&lt;/code&gt; Vue detail view and hasn't committed yet. Adding a field means re-running the generator with &lt;code&gt;--force&lt;/code&gt; over files Sam touched. So Sam asks for a belt &lt;strong&gt;and&lt;/strong&gt; suspenders:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add an &lt;code&gt;originCountry&lt;/code&gt; (string) to &lt;code&gt;Franchise&lt;/code&gt;. Take a backup first so I can roll back if it stomps my edits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two things happen. The agent reads the current &lt;code&gt;Franchise&lt;/code&gt; (via the project's entities resource) and re-declares it with &lt;strong&gt;all&lt;/strong&gt; its existing fields plus &lt;code&gt;originCountry&lt;/code&gt; — re-declaring an entity in JDL replaces it, and the agent knows not to emit a half-defined one, so title/synopsis/status/startYear survive. And because Sam asked for a backup, the server snapshots the project into a temp folder &lt;em&gt;before&lt;/em&gt; the &lt;code&gt;--force&lt;/code&gt; run and hands back a paste-ready escape route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Backup taken before this run: /tmp/jhipster-mcp-backup-otakushelf-9fA2
To roll back:
  cp -R "/tmp/jhipster-mcp-backup-otakushelf-9fA2/." "/Users/sam/projects/otakushelf/" &amp;amp;&amp;amp; rm -rf "/tmp/jhipster-mcp-backup-otakushelf-9fA2"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a plain backup directory, not git — the MCP never touches Sam's repo. (Honestly, if Sam's tree had been clean, a commit would've done the same job; the backup is for exactly this not-committed-yet situation.) As it turns out the regeneration is clean and Sam's edit survives, so the backup goes unused — which is the best kind of safety net.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the receipts
&lt;/h2&gt;

&lt;p&gt;Sam doesn't take "done!" on faith. Every time the agent runs the generator, the MCP hands back two things: the human-readable output Sam knows from the terminal, &lt;em&gt;and&lt;/em&gt; a small structured summary the agent actually reasons over — exit code, success flag, the list of files changed, any warnings, and (when taken) that backup path. So when the agent reports "added &lt;code&gt;originCountry&lt;/code&gt;, 9 files changed, no conflicts," it's reading those numbers off real data, not vibing. That's why Sam can trust a one-line summary instead of re-reading a wall of &lt;code&gt;create&lt;/code&gt;/&lt;code&gt;force&lt;/code&gt; lines.&lt;/p&gt;

&lt;p&gt;For a broader sanity check, Sam asks for the dashboard:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What's the current setup of OtakuShelf — versions, database, entities?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;info&lt;/code&gt; tool runs &lt;code&gt;jhipster info&lt;/code&gt; and lays it out: JHipster 9.0.0, PostgreSQL, and the full entity list — Franchise, BookSeries, Book, Anime, Season, Episode. Everything Sam expects, nothing it doesn't. (There was also a steady trickle of progress lines during each generation, by the way — so the longer runs never felt like a hang, just JHipster doing its thing.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;OtakuShelf is now a tidy, paginated, DTO-backed catalog of manga and anime, and Sam has a comfortable rhythm: describe the change, validate, dry-run, apply, occasionally with a backup. Then JHipster ships &lt;strong&gt;9.1.0&lt;/strong&gt;. In the old days that release note would trigger a small dread. Next, Sam finds out whether an agent makes a version upgrade boring too.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Next in the series: "Upgrading OtakuShelf to JHipster 9.1.0" — scoping and previewing a version bump, git-free, before a single file changes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jhipster</category>
      <category>ai</category>
      <category>java</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Adding the anime side without holding my breath</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Wed, 27 May 2026 21:42:34 +0000</pubDate>
      <link>https://dev.to/avdev4j/24-adding-the-anime-side-without-holding-my-breath-1617</link>
      <guid>https://dev.to/avdev4j/24-adding-the-anime-side-without-holding-my-breath-1617</guid>
      <description>&lt;p&gt;A week later, OtakuShelf has a few franchises and their manga in it. Now Sam wants the other half: anime. That means new entities — &lt;code&gt;Anime&lt;/code&gt;, &lt;code&gt;Season&lt;/code&gt;, &lt;code&gt;Episode&lt;/code&gt; — wired into the existing &lt;code&gt;Franchise&lt;/code&gt;. The difference from last time is important: this is a &lt;strong&gt;live project&lt;/strong&gt; with data and a model Sam cares about. Running the generator blind on it is how you end up with a clobbered entity and a bad afternoon. So Sam slows down by exactly one habit: preview first.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick gut-check before anything else
&lt;/h2&gt;

&lt;p&gt;Before even applying, Sam sketches the new shape and asks the agent to validate it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Validate this without changing anything: an &lt;code&gt;Anime&lt;/code&gt; (title, studio) linked many-to-one to &lt;code&gt;Franchise&lt;/code&gt;, a &lt;code&gt;Season&lt;/code&gt; (number, title, episode count) under an anime, and an &lt;code&gt;Episode&lt;/code&gt; (number, title, air date, duration in minutes) under a season.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;validate_jdl&lt;/code&gt; tool runs a fast local lint first (is the JDL even well-formed?), then &lt;em&gt;generates the whole thing in a throwaway directory&lt;/em&gt; and reports any error — all without touching OtakuShelf. It comes back clean. Good: the idea is sound. Now, what would it actually &lt;em&gt;do&lt;/em&gt; to the project?&lt;/p&gt;

&lt;h2&gt;
  
  
  The dry run that's actually dry
&lt;/h2&gt;

&lt;p&gt;Here's the part every JHipster veteran needs to hear, because it bit us too: in &lt;strong&gt;JHipster 9, &lt;code&gt;--dry-run&lt;/code&gt; still writes files.&lt;/strong&gt; It only prints conflicts. So you cannot trust that flag to keep your project pristine.&lt;/p&gt;

&lt;p&gt;The MCP sidesteps the whole problem. When Sam asks for a preview:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In &lt;code&gt;/Users/sam/projects/otakushelf&lt;/code&gt;, show me what adding the anime entities and their relationships would change — don't write anything yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;…the agent calls the apply tool with &lt;code&gt;dryRun: true&lt;/code&gt;, and the server does something more honest than a flag: it makes a temp directory, copies OtakuShelf's &lt;code&gt;.yo-rc.json&lt;/code&gt; and existing entities into it for fidelity, generates &lt;em&gt;there&lt;/em&gt;, lists what would change, and throws the temp away. The real project sees &lt;strong&gt;zero&lt;/strong&gt; writes. Sam reads the file list — new &lt;code&gt;Anime&lt;/code&gt;, &lt;code&gt;Season&lt;/code&gt;, &lt;code&gt;Episode&lt;/code&gt; sources, updated Liquibase changelogs, a couple of Vue components — nods, and only &lt;em&gt;then&lt;/em&gt; drops the &lt;code&gt;dryRun&lt;/code&gt;. The exact same call, now for real.&lt;/p&gt;

&lt;p&gt;This is the rhythm Sam settles into for the rest of the project: &lt;strong&gt;validate → dry-run → apply.&lt;/strong&gt; It costs a few seconds and removes all the adrenaline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent already knows the shelf
&lt;/h2&gt;

&lt;p&gt;There's a quieter thing happening that makes this safe. When Sam says "link &lt;code&gt;Anime&lt;/code&gt; to &lt;code&gt;Franchise&lt;/code&gt;," the agent doesn't guess what &lt;code&gt;Franchise&lt;/code&gt; looks like — it reads the project's current entities through a resource (&lt;code&gt;jhipster://project/entities&lt;/code&gt;). So it knows &lt;code&gt;Franchise&lt;/code&gt; already exists with its title/synopsis/status/startYear, and it adds the relationship &lt;em&gt;without&lt;/em&gt; redefining and accidentally trimming those fields. It's working from the real model, not from a fuzzy memory of last week's chat.&lt;/p&gt;

&lt;p&gt;For this batch Sam lets the agent do it all in one shot — three new entities and their relationships belong together, so the agent composes a single &lt;code&gt;import_jdl&lt;/code&gt; call instead of three separate ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entity Anime { title String required, studio String }
entity Season { number Integer required min(1), title String, episodeCount Integer min(0) }
entity Episode { number Integer required min(1), title String, airDate LocalDate, durationMinutes Integer min(0) }

relationship OneToMany {
  Franchise{animes} to Anime{franchise}
  Anime{seasons} to Season{anime}
  Season{episodes} to Episode{season}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One generator run, one diff to review. (If Sam had wanted just a single entity, there's an &lt;code&gt;add_entity&lt;/code&gt; tool that builds the JDL from a plain description — handy for one-offs. For a coordinated batch like this, one &lt;code&gt;import_jdl&lt;/code&gt; is tidier and faster.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the preview habit pays off here specifically
&lt;/h2&gt;

&lt;p&gt;The anime side &lt;em&gt;touches&lt;/em&gt; the manga side — &lt;code&gt;Franchise&lt;/code&gt; gains an &lt;code&gt;animes&lt;/code&gt; collection. That's precisely the kind of cross-cutting change where a blind regeneration makes you nervous. With the dry run, Sam saw in advance that &lt;code&gt;Franchise.java&lt;/code&gt; and its Vue views would be regenerated, confirmed nothing surprising was in the list, and proceeded with a clear conscience. The MCP didn't make the change safe by being clever; it made it safe by letting Sam &lt;em&gt;look first&lt;/em&gt;, for free, as many times as wanted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;OtakuShelf now models both halves of a franchise — manga and anime — from &lt;code&gt;Franchise&lt;/code&gt; down to individual &lt;code&gt;Episode&lt;/code&gt;s. It works, but it's a little rough: no DTOs, and Sam already realized a field is missing. Next, the polish pass — and a look at how to read what the agent actually did to your code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Next in the series: "Polishing the catalog (and reading the agent's receipts)" — options, a forgotten field with a backup, and trusting what the agent did.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jhipster</category>
      <category>ai</category>
      <category>java</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Pairing up: scaffolding OtakuShelf with an agent</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Wed, 27 May 2026 21:41:51 +0000</pubDate>
      <link>https://dev.to/avdev4j/14-pairing-up-scaffolding-otakushelf-with-an-agent-4j4h</link>
      <guid>https://dev.to/avdev4j/14-pairing-up-scaffolding-otakushelf-with-an-agent-4j4h</guid>
      <description>&lt;p&gt;Sam has shipped a dozen JHipster apps the old-fashioned way: open an editor, write the JDL, run the CLI, answer its questions, repeat. This time Sam wants to try something different — keep the JHipster expertise, but hand the typing to an AI agent. The guinea pig is a personal project that's been on the back burner forever: &lt;strong&gt;OtakuShelf&lt;/strong&gt;, an app to catalog manga and anime, grouped by franchise. &lt;em&gt;Naruto&lt;/em&gt; is one franchise — it has a manga side and an anime side, and Sam wants both under one roof.&lt;/p&gt;

&lt;h2&gt;
  
  
  The agent needs hands
&lt;/h2&gt;

&lt;p&gt;An AI agent is great at turning "a franchise has many book series" into correct JDL. What it &lt;em&gt;can't&lt;/em&gt; do on its own is run your &lt;code&gt;jhipster&lt;/code&gt; binary. That's the gap the &lt;strong&gt;JHipster MCP&lt;/strong&gt; fills: it's a small server that exposes JHipster to the agent as a set of safe actions. Three flavors, and that's the whole mental model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tools&lt;/strong&gt; — things the agent &lt;em&gt;does&lt;/em&gt; (scaffold, add an entity, validate);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resources&lt;/strong&gt; — things the agent &lt;em&gt;reads&lt;/em&gt; (the JDL grammar, your project's current entities);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;prompts&lt;/strong&gt; — ready-made recipes &lt;em&gt;you&lt;/em&gt; launch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crucially, it doesn't bundle JHipster — it drives the &lt;strong&gt;same global &lt;code&gt;jhipster&lt;/code&gt;&lt;/strong&gt; Sam already has (version 9.0.0 here). So nothing about the generator changes; the agent just operates it, non-interactively.&lt;/p&gt;

&lt;p&gt;Wiring it into Sam's editor is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add jhipster &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; jhipster-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart, confirm the tools show up, done. (Other hosts and options live in the &lt;a href="https://github.com/avdev4j/jhipster-mcp/blob/main/docs/02-installation.md" rel="noopener noreferrer"&gt;install guide&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  One sentence, one monolith
&lt;/h2&gt;

&lt;p&gt;Sam decides to start with just the &lt;strong&gt;manga side&lt;/strong&gt; — get the shape right before piling on anime. So:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a JHipster monolith in &lt;code&gt;/Users/sam/projects/otakushelf&lt;/code&gt; called &lt;code&gt;otakushelf&lt;/code&gt;: JWT auth, PostgreSQL in prod with H2 in dev, Vue, Maven, package &lt;code&gt;com.otakushelf&lt;/code&gt;. Add a &lt;code&gt;Franchise&lt;/code&gt; (title, synopsis, a status that's ONGOING/COMPLETED/HIATUS, start year), a &lt;code&gt;BookSeries&lt;/code&gt; (title, total volumes), and a &lt;code&gt;Book&lt;/code&gt; (title, volume number, release date). A franchise has many book series; a book series has many books. Paginate everything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent first glances at the &lt;code&gt;jhipster://docs/jdl-grammar&lt;/code&gt; resource so it doesn't fumble syntax, then builds one JDL document and calls the &lt;code&gt;create_app_from_jdl&lt;/code&gt; tool with roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;application {
  config {
    baseName otakushelf
    applicationType monolith
    authenticationType jwt
    databaseType sql
    prodDatabaseType postgresql
    devDatabaseType h2Disk
    clientFramework vue
    buildTool maven
    packageName com.otakushelf
  }
  entities *
}

enum FranchiseStatus { ONGOING, COMPLETED, HIATUS }

entity Franchise { title String required, synopsis TextBlob, status FranchiseStatus, startYear Integer }
entity BookSeries { title String required, totalVolumes Integer min(0) }
entity Book { title String, volumeNumber Integer required min(1), releaseDate LocalDate }

relationship OneToMany {
  Franchise{bookSeries} to BookSeries{franchise}
  BookSeries{books} to Book{bookSeries}
}

paginate * with pagination
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A minute later (PostgreSQL, a Vue front-end, and an &lt;code&gt;npm install&lt;/code&gt; aren't instant), OtakuShelf exists. Sam didn't write a line of JDL — but, being Sam, read every line the agent did.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Here" is not a place
&lt;/h2&gt;

&lt;p&gt;One habit to build immediately: the MCP has &lt;strong&gt;no current directory&lt;/strong&gt;. Every tool wants an absolute &lt;code&gt;workingDirectory&lt;/code&gt;, and &lt;code&gt;create_app_from_jdl&lt;/code&gt; flatly refuses to scribble into a folder that isn't empty. "Make me an app here" goes nowhere; "make me an app in &lt;code&gt;/Users/sam/projects/otakushelf&lt;/code&gt;" works. Say &lt;em&gt;where&lt;/em&gt;, every time. (It's also a nice guardrail — the agent can't wander off and generate in some surprising place.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, how do I actually run this thing?
&lt;/h2&gt;

&lt;p&gt;The files exist, but the MCP draws a hard line: it scaffolds and edits, it does &lt;strong&gt;not&lt;/strong&gt; build, run, start, or git-commit your app. That's your shell's job, on purpose. So Sam asks the obvious follow-up:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What are the build and run commands for &lt;code&gt;/Users/sam/projects/otakushelf&lt;/code&gt;?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;project_commands&lt;/code&gt; tool reads the project and answers from &lt;em&gt;facts&lt;/em&gt; — it sees Maven with the wrapper present and a Vue &lt;code&gt;package.json&lt;/code&gt;, so it reports &lt;code&gt;./mvnw&lt;/code&gt; to start the backend, &lt;code&gt;npm install&lt;/code&gt; then &lt;code&gt;npm start&lt;/code&gt; for the Vue dev server, &lt;code&gt;./mvnw verify&lt;/code&gt; for tests, and so on — and reminds Sam it's reporting these, not running them. Two terminals later, OtakuShelf is live at &lt;code&gt;localhost:8080&lt;/code&gt;, empty and waiting for its first franchise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;In one sitting Sam went from empty folder to a running, paginated CRUD app for the manga side — by describing it, not typing it. But a catalog of manga without anime is only half a shelf. Next, Sam comes back to a &lt;em&gt;live&lt;/em&gt; project to add the anime side — and that's where a careful developer reaches for previews before touching anything.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Next in the series: "Adding the anime side without holding my breath" — coming back to a live project to add the anime entities, previewing every change first.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jhipster</category>
      <category>ai</category>
      <category>java</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Drive JHipster with your AI agent: introducing jhipster-mcp (v0.0.4)</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Tue, 26 May 2026 23:08:35 +0000</pubDate>
      <link>https://dev.to/avdev4j/building-a-jhipster-mcp-server-let-ai-agents-scaffold-and-evolve-your-architecture-487e</link>
      <guid>https://dev.to/avdev4j/building-a-jhipster-mcp-server-let-ai-agents-scaffold-and-evolve-your-architecture-487e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — &lt;code&gt;jhipster-mcp&lt;/code&gt; is an open-source &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; server that lets an AI agent generate and evolve &lt;a href="https://www.jhipster.tech" rel="noopener noreferrer"&gt;JHipster&lt;/a&gt; applications for you. You describe what you want in plain language; the agent writes JDL and drives the JHipster CLI. It's on npm — point your MCP host at it with one line. &lt;strong&gt;v0.0.4 is the first public release.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📦 npm: &lt;a href="https://www.npmjs.com/package/jhipster-mcp" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/jhipster-mcp&lt;/a&gt;&lt;br&gt;
🧑‍💻 GitHub: &lt;a href="https://github.com/avdev4j/jhipster-mcp" rel="noopener noreferrer"&gt;https://github.com/avdev4j/jhipster-mcp&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;JHipster has always been about &lt;em&gt;speed&lt;/em&gt;: scaffold a production-grade Spring Boot + modern frontend app in minutes, model your domain with &lt;strong&gt;JDL&lt;/strong&gt; (JHipster Domain Language), and let the generator write the boilerplate.&lt;/p&gt;

&lt;p&gt;AI coding agents are great at &lt;em&gt;intent&lt;/em&gt;: you tell them what you want, they figure out the steps.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jhipster-mcp&lt;/code&gt; connects the two. It exposes JHipster as a set of &lt;strong&gt;MCP tools&lt;/strong&gt; an agent can call. So instead of remembering JDL syntax and CLI flags, you say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Create a JHipster monolith in &lt;code&gt;/tmp/shop&lt;/code&gt; with PostgreSQL and an Angular frontend, plus a &lt;code&gt;Product&lt;/code&gt; entity (name, price) and a &lt;code&gt;Category&lt;/code&gt; with a one-to-many to products. Paginate everything."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;…and the agent composes valid JDL, runs the generator, and streams the result back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Goals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make JHipster conversational.&lt;/strong&gt; Natural-language intent → correct JDL → real generated code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stay safe and predictable.&lt;/strong&gt; Non-interactive, no shell, validated input, no surprise writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be machine-friendly.&lt;/strong&gt; Return structured results an agent can reason about, not just logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lean on JHipster, don't reinvent it.&lt;/strong&gt; It spawns &lt;em&gt;your&lt;/em&gt; JHipster CLI; the generator stays the source of truth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who it's for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JHipster developers&lt;/strong&gt; who want to scaffold and evolve apps faster from their AI editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teams&lt;/strong&gt; standardising on JHipster who want guardrails around how the generator is invoked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI / MCP tinkerers&lt;/strong&gt; curious about wrapping a real, stateful developer CLI as MCP tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you use &lt;strong&gt;Claude Code&lt;/strong&gt;, &lt;strong&gt;Claude Desktop&lt;/strong&gt;, &lt;strong&gt;Cursor&lt;/strong&gt;, or any MCP-compatible host, you can plug it in today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do with it
&lt;/h2&gt;

&lt;p&gt;The server ships &lt;strong&gt;9 tools&lt;/strong&gt;, JDL-first:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;create_app_from_jdl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scaffold a brand-new app from a full JDL block.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;import_jdl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply JDL (entities, relationships, options) to an existing project.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add_entity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add one entity with fields, validations, and per-entity options.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;add_relationship&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add a typed relationship between two entities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;set_option&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle JDL options (&lt;code&gt;paginate&lt;/code&gt;, &lt;code&gt;dto&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, …).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validate_jdl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check JDL for errors &lt;strong&gt;without modifying anything&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generate_ci_cd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scaffold a CI/CD pipeline (GitHub, GitLab, Jenkins, …).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inspect project versions, config, and entities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run_jhipster&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Escape hatch — run an allowlisted subcommand safely.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It also exposes a &lt;strong&gt;JDL grammar cheat-sheet&lt;/strong&gt; as an MCP resource, so the agent writes valid JDL on the first try.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in v0.0.4 — the highlights
&lt;/h2&gt;

&lt;p&gt;This first release focuses on making &lt;strong&gt;every tool call trustworthy and legible&lt;/strong&gt; to the agent:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔄 Live progress streaming
&lt;/h3&gt;

&lt;p&gt;Full app generation can take 30–90 seconds. Instead of looking frozen, the server streams the generator's output as MCP &lt;strong&gt;progress notifications&lt;/strong&gt; in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Validation + a &lt;em&gt;true&lt;/em&gt; dry-run
&lt;/h3&gt;

&lt;p&gt;You can validate JDL or preview a change without touching your project.&lt;/p&gt;

&lt;p&gt;There's a fun gotcha here: JHipster's own &lt;code&gt;--dry-run&lt;/code&gt; flag only &lt;em&gt;prints conflicts&lt;/em&gt; — &lt;strong&gt;it still writes files&lt;/strong&gt; (I confirmed this against the real CLI). So a flag-based "preview" would silently modify your project. &lt;code&gt;jhipster-mcp&lt;/code&gt; instead does a &lt;strong&gt;real preview&lt;/strong&gt;: it generates in a throwaway temp directory (copying your project's &lt;code&gt;.yo-rc.json&lt;/code&gt; and &lt;code&gt;.jhipster/&lt;/code&gt; for context), parses what &lt;em&gt;would&lt;/em&gt; be produced, and discards everything. Your project is never modified.&lt;/p&gt;

&lt;h3&gt;
  
  
  📦 Structured output
&lt;/h3&gt;

&lt;p&gt;Every tool returns machine-readable JSON alongside the human-readable text, so the agent reasons on data instead of scraping logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jhipster jdl changes.jdl --force --skip-git"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exitCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dryRun"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Customer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Order"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filesChanged"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/main/java/..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warnings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why it's safe by design
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No shell.&lt;/strong&gt; The CLI is spawned with &lt;code&gt;shell: false&lt;/code&gt; and an argument allowlist — no command injection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validated JDL builders.&lt;/strong&gt; Entity/field/type names are checked against strict patterns before any JDL is written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-interactive always.&lt;/strong&gt; Runs with &lt;code&gt;--force --skip-git&lt;/code&gt; and &lt;code&gt;CI=true&lt;/code&gt;; never hangs on a prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded.&lt;/strong&gt; Every tool takes an explicit &lt;code&gt;workingDirectory&lt;/code&gt;; the server won't act outside it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under the hood it's &lt;strong&gt;TypeScript&lt;/strong&gt; on the official &lt;strong&gt;MCP SDK&lt;/strong&gt;, with 70 tests and CI on Node 22/24.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 20+&lt;/li&gt;
&lt;li&gt;A working global JHipster CLI:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; generator-jhipster
  jhipster &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Add it to your MCP host
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Claude Code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add jhipster &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; jhipster-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Claude Desktop / Cursor / others&lt;/strong&gt; — add to your MCP config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jhipster"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jhipster-mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No clone, no build — &lt;code&gt;npx&lt;/code&gt; fetches and caches the package for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Just ask
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"In &lt;code&gt;/Users/me/projects/shop&lt;/code&gt;, add a &lt;code&gt;Customer&lt;/code&gt; entity with firstName (required, 2–50 chars), lastName, and email, then a one-to-many from Customer to Order."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent reads the JDL grammar, builds the snippet, and applies it — streaming progress as it goes.&lt;/p&gt;

&lt;p&gt;Want to look before you leap? Ask it to &lt;strong&gt;preview&lt;/strong&gt; first:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Show me what adding a &lt;code&gt;Tag&lt;/code&gt; entity would change — don't write anything yet."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;…and it runs the same tool with &lt;code&gt;dryRun: true&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;This release completes the "Tier 1" experience work (progress, validation/dry-run, structured output). On the roadmap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project-state resources&lt;/strong&gt; — let the agent read &lt;code&gt;.yo-rc.json&lt;/code&gt;, the entity list, and exported JDL directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guided prompts&lt;/strong&gt; — reusable workflows like "scaffold a CRUD monolith" or "convert to microservices".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe-apply with rollback&lt;/strong&gt;, elicitation for missing config, and sandboxing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; jhipster-mcp@0.0.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⭐ Star it, break it, and tell me what's missing: &lt;a href="https://github.com/avdev4j/jhipster-mcp" rel="noopener noreferrer"&gt;https://github.com/avdev4j/jhipster-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built with ❤️ for the JHipster community.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;#jhipster #ai #mcp #java #springboot #opensource&lt;/em&gt;&lt;/p&gt;

</description>
      <category>jhipster</category>
      <category>ai</category>
      <category>mcp</category>
      <category>java</category>
    </item>
    <item>
      <title>The AI Triforce of seed4j: Power, Wisdom, and Courage for Your Dev Agent</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Mon, 25 May 2026 11:12:20 +0000</pubDate>
      <link>https://dev.to/avdev4j/the-ai-triforce-of-seed4j-power-wisdom-and-courage-for-your-dev-agent-2mlb</link>
      <guid>https://dev.to/avdev4j/the-ai-triforce-of-seed4j-power-wisdom-and-courage-for-your-dev-agent-2mlb</guid>
      <description>&lt;h1&gt;
  
  
  The AI Triforce of Seed4j: Power, Wisdom, and Courage for Your Dev Agent
&lt;/h1&gt;

&lt;p&gt;In the Legend of Zelda, the Triforce is the ultimate relic: three golden triangles that together grant the wish of whoever holds them. Alone, each fragment is dangerous in the wrong hands. Together, they bring balance to Hyrule.&lt;/p&gt;

&lt;p&gt;I've been thinking about Seed4j's relationship with AI agents through that lens. Not as a finished story, but as a reflection. What would it take to make Seed4j truly AI-native? What are the three fragments we need to forge?&lt;/p&gt;

&lt;p&gt;This article is that reflection.&lt;/p&gt;

&lt;p&gt;Seed4j is an open-source application generator built around hexagonal architecture. It scaffolds the structure (ports, adapters, configuration, modules) but deliberately stops there. It has never generated business code, and that's a conscious design decision. The domain logic belongs to the developer. Seed4j hands you a well-structured, empty shell, and you fill it.&lt;/p&gt;

&lt;p&gt;At the era of AI agents, that boundary gets interesting. An agent &lt;em&gt;can&lt;/em&gt; write business code. The question is: can Seed4j guide it to do so correctly, within its own philosophy? Can the agent become the missing piece, not replacing Seed4j's intentional silence, but completing it?&lt;/p&gt;

&lt;p&gt;That's what led me to think about three principles: the &lt;strong&gt;MCP&lt;/strong&gt; (Power), the &lt;strong&gt;Harness&lt;/strong&gt; (Wisdom), and the &lt;strong&gt;Skills&lt;/strong&gt; (Courage). Together, they sketch what a &lt;em&gt;Seed4j augmented&lt;/em&gt; might look like, an AI-compatible version of the project, without betraying what makes it Seed4j.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fragment 1: The MCP, The Triforce of Power
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Power without direction destroys. Power with the right interface builds."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first question is simple: how does an AI agent actually &lt;em&gt;do&lt;/em&gt; something with Seed4j, rather than just talk about it?&lt;/p&gt;

&lt;p&gt;The answer is a &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; server, &lt;code&gt;seed4j-mcp&lt;/code&gt;. MCP is an open standard that lets AI agents call tools exposed by external servers. Instead of a human typing commands into a CLI, an MCP-aware agent (Claude Code, Claude Desktop, Cursor, and others) can discover and invoke Seed4j's functionality directly.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;seed4j-mcp&lt;/code&gt; server exposes a set of tools that map to the full Seed4j workflow:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List every available module, grouped by category&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keyword search across slugs, descriptions, and tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_module_details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Property definitions for a given module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_module_dependencies&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prerequisite graph before applying a module&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validate_properties&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dry-run schema check (no side effects)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_presets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Curated pre-ordered stacks (e.g. "Webapp: Vue + Spring Boot")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apply_preset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resolve a preset and apply all its modules in one call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;create_project&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Initialize a new base project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apply_modules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply an ordered list of modules in a single batch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A typical agent flow: &lt;code&gt;list_presets&lt;/code&gt; → &lt;code&gt;get_preset_details&lt;/code&gt; → &lt;code&gt;apply_preset&lt;/code&gt;. Or for a custom stack: &lt;code&gt;search_modules&lt;/code&gt; → &lt;code&gt;get_module_dependencies&lt;/code&gt; → &lt;code&gt;validate_properties&lt;/code&gt; → &lt;code&gt;apply_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The MCP server acts as a &lt;strong&gt;boundary layer&lt;/strong&gt;. The agent doesn't need to understand Seed4j's internals, it just needs to know what tools exist and what they accept. Every action goes through a defined, typed interface. Power, channeled.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗡️ What could be done
&lt;/h3&gt;

&lt;p&gt;Publish &lt;code&gt;seed4j-mcp&lt;/code&gt; to the &lt;a href="https://github.com/modelcontextprotocol/servers" rel="noopener noreferrer"&gt;official MCP registry&lt;/a&gt;, so any agent, regardless of the client, can discover and wire up Seed4j with a single reference. This is the lowest-friction path to making Seed4j a first-class citizen in the AI agent ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fragment 2: The Harness, The Triforce of Wisdom
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Wisdom is knowing where you are, what the rules are, and what not to touch."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even with the right tools, an agent can still drift. It might apply modules out of order, ignore architectural conventions, or, worse, start writing code where it doesn't belong. Raw power without wisdom is Ganondorf with the Triforce: capable of anything, guided by nothing.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Harness&lt;/strong&gt; is how we give the agent a sense of place.&lt;/p&gt;

&lt;p&gt;In practice, a harness is a set of files that speak directly to the agent, not documentation written for humans but context written for AI. The most common form today is a file like &lt;code&gt;CLAUDE.md&lt;/code&gt;, which Claude Code reads automatically at the start of every session. It tells the agent what the project is, what conventions govern it, and what it should or should not attempt on its own.&lt;/p&gt;

&lt;p&gt;Here's where Seed4j has an interesting starting point: it already generates a &lt;code&gt;/documentation&lt;/code&gt; folder inside every project. That folder contains explanations of the hexagonal architecture, the module system, and how the generated structure is meant to be used. It was written for developers, but it could become the foundation of an AI-oriented harness.&lt;/p&gt;

&lt;p&gt;That's the gap worth closing. The documentation exists, but it wasn't designed with an agent in mind. An AI-ready harness would go further: explaining not just &lt;em&gt;what&lt;/em&gt; Seed4j generated, but &lt;em&gt;how an agent should reason about it&lt;/em&gt;. Which parts of the codebase are Seed4j's territory (don't touch), which parts are the agent's responsibility (the domain), and where the boundary between the two sits.&lt;/p&gt;

&lt;p&gt;This matters because Seed4j's hexagonal structure has a clear separation of concerns (ports, adapters, domain, application layer) and an agent that doesn't understand that separation will eventually violate it. Not out of malice, but out of ignorance. The harness is what turns ignorance into awareness.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗡️ What could be done
&lt;/h3&gt;

&lt;p&gt;Generate an AI-oriented documentation layer alongside the existing &lt;code&gt;/documentation&lt;/code&gt; folder, in a dedicated &lt;code&gt;/ai-context&lt;/code&gt; (or similar) that describes the architecture, the conventions, and the agent's role in terms an LLM can act on. Unlike the existing docs, this wouldn't be written for a developer to read linearly; it would be structured to be loaded as context at the start of an agent session, answering the questions the agent would otherwise guess at.&lt;/p&gt;

&lt;p&gt;📄 Example: &lt;code&gt;.ai/context.md&lt;/code&gt; generated by Seed4j&lt;/p&gt;

&lt;pre&gt;
# Seed4j Project Context

&amp;gt; This file is auto-generated by Seed4j. Do not edit manually.
&amp;gt; Re-generated on every `seed4j apply` command.
&amp;gt; Applied modules history: see `.seed4j/modules/history.json`

## Project
- Name: my-app
- Architecture: Hexagonal (Ports &amp;amp; Adapters)

## Package structure
com.example.myapp
├── domain/
│   ├── model/         ← business entities, pure Java, no framework
│   └── port/
│       ├── in/        ← use case interfaces (input ports)
│       └── out/       ← repository interfaces (output ports)
├── application/       ← use case implementations
└── infrastructure/
    └── adapter/
        ├── in/rest/   ← REST controllers (Spring MVC)
        └── out/persistence/ ← JPA repositories and entities

## What Seed4j owns — do not modify
- All configuration files (application.yml, pom.xml, Docker files)
- Infrastructure wiring and module setup
- Base package structure and adapter boilerplate

## What you (the agent) are responsible for
- Domain model: entities and value objects in domain/model/
- Ports: use case and repository interfaces in domain/port/
- Use cases: business logic implementations in application/
- Adapters: framework wiring in infrastructure/adapter/

## Rules
- NEVER import infrastructure or framework classes into domain/ or application/
- NEVER implement business logic in adapters
- ALWAYS go through a port interface, never call an adapter directly
- Run `./mvnw test` after each implementation step

## Available skills
- .ai/skills/hexagonal-feature.md  → implement a business feature end-to-end
- .ai/skills/apply-module.md       → safely apply a new Seed4j module
- .ai/skills/tdd-domain.md         → TDD workflow for domain logic
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 There is no universal standard for AI context folders yet. &lt;code&gt;.ai/&lt;/code&gt; is a pragmatic choice: readable, non-conflicting with existing tools, and scoped to the project. A root-level &lt;code&gt;CLAUDE.md&lt;/code&gt; or &lt;code&gt;AGENTS.md&lt;/code&gt; can simply point to &lt;code&gt;.ai/context.md&lt;/code&gt; for compatibility with agents that expect a specific filename.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fragment 3: The Skills, The Triforce of Courage
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Courage isn't acting blindly. It's knowing the path and walking it, step by step."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where the reflection gets most interesting, and where Seed4j's design philosophy creates the most productive tension.&lt;/p&gt;

&lt;p&gt;Seed4j gives you a shell. A well-architected, hexagonal, configuration-complete shell, but a shell. It has never generated business logic, and it never will. That's not a limitation; it's a statement. The domain belongs to the developer.&lt;/p&gt;

&lt;p&gt;But here's the question worth sitting with: &lt;em&gt;if an AI agent can write the domain code, who teaches it to do so correctly within Seed4j's framework?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's the role of &lt;strong&gt;Skills&lt;/strong&gt;: not tools (those are the MCP's job), not context (that's the Harness), but workflow. Step-by-step guidance for complex, multi-stage tasks that live in the space Seed4j deliberately leaves empty.&lt;/p&gt;

&lt;p&gt;Link didn't walk into Ganon's castle on day one. He completed the dungeons in order, acquired the right items, and followed the critical path. A skill is the dungeon map: a structured sequence the agent follows to reach a goal without going off the rails.&lt;/p&gt;

&lt;p&gt;For Seed4j, skills could operate at two levels:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Module-level skills&lt;/strong&gt;: guiding the agent through the correct application of Seed4j modules. Apply in the right order, resolve dependencies, validate before committing. This is the mechanical layer: making sure the shell is assembled correctly before writing a single line of business code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature-level skills&lt;/strong&gt;: this is the more ambitious and more interesting layer. A skill that guides an agent through implementing a business feature the Seed4j way: domain object first, then the use case, then the port, then the adapter, tests at every step. Or a TDD-oriented skill: write the failing test, implement the minimum domain logic, make it pass, then wire the infrastructure. All of it respecting the hexagonal boundaries that Seed4j established.&lt;/p&gt;

&lt;p&gt;The agent doesn't replace the developer's judgment, it follows a workflow that encodes that judgment. Seed4j's silence on business code wasn't a gap; it was a boundary. Skills are what allow an AI agent to operate inside that boundary without erasing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗡️ What could be done
&lt;/h3&gt;

&lt;p&gt;Develop a library of Seed4j skills for common agent workflows, starting with the most frequent pain points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Module application skill&lt;/strong&gt;: apply a module correctly, resolve its dependency graph, validate before committing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hexagonal feature skill&lt;/strong&gt;: implement a business feature end-to-end following the hexagonal layering Seed4j establishes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TDD skill&lt;/strong&gt;: red-green-refactor loop with an AI agent, domain-first, infrastructure last.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These skills would live in the Seed4j ecosystem and be referenced by the harness, so the agent knows they exist and when to invoke them.&lt;/p&gt;

&lt;p&gt;📄 Example: &lt;code&gt;hexagonal-feature.md&lt;/code&gt; skill&lt;/p&gt;

&lt;pre&gt;
# Skill: Implement a Hexagonal Feature

## Goal
Guide the agent through implementing a business feature
respecting Seed4j's hexagonal architecture boundaries.

## Prerequisites
- Project initialized with Seed4j base module
- Persistence module applied (`seed4j apply persistence`)

## Steps

### 1. Define the domain object
- Create the entity in `src/main/java/{package}/domain/model/`
- Pure Java: no framework annotations, no infrastructure imports
- Write a unit test before implementing (red phase)

### 2. Define the ports
- Create the input port (use case interface) in `domain/port/in/`
- Create the output port (repository interface) in `domain/port/out/`
- Ports are Java interfaces only, no implementation here

### 3. Implement the use case
- Implement the input port in `application/`
- Inject the output port by interface, never the adapter directly
- Write the unit test (mock the output port), then implement

### 4. Implement the adapter
- Persistence adapter in `infrastructure/adapter/out/persistence/`
- REST adapter (if REST module applied) in `infrastructure/adapter/in/rest/`
- Wire to the framework (JPA, Spring MVC, Quarkus REST...)

## Rules
- NEVER import infrastructure classes into `domain/` or `application/`
- NEVER skip the port layer to call an adapter directly
- ALWAYS write the failing test before the implementation
- If a layer doesn't exist yet, check which Seed4j module provides it

## Notes
This skill is available because the persistence module is applied.
If the REST module is also applied, expose the use case via a REST adapter in step 4.
&lt;/pre&gt;

&lt;h2&gt;
  
  
  The Triforce, Complete
&lt;/h2&gt;

&lt;p&gt;These three fragments are not independent: they form a system, and each one only makes full sense in relation to the others.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;MCP&lt;/strong&gt; (Power) gives the agent the ability to act on Seed4j. The &lt;strong&gt;Harness&lt;/strong&gt; (Wisdom) anchors it in the reality of the project: its architecture, its conventions, its boundaries. The &lt;strong&gt;Skills&lt;/strong&gt; (Courage) guide it through the workflows that Seed4j intentionally leaves to the developer, without violating the philosophy that makes Seed4j what it is.&lt;/p&gt;

&lt;p&gt;Strip any fragment away and the balance breaks. Power without Wisdom is chaos. Wisdom without Courage is paralysis. Courage without Power is intention without effect.&lt;/p&gt;

&lt;p&gt;What excites me about this vision is that it doesn't ask Seed4j to become something it's not. It doesn't generate business code, the agent does. It doesn't instruct the developer, the skills do. Seed4j remains the generator of structure. The Triforce is what makes that structure legible to an agent, navigable in its architecture, and extensible through AI-guided workflows.&lt;/p&gt;

&lt;p&gt;This is a reflection, not a roadmap. But it feels like the right direction for a &lt;em&gt;Seed4j augmented&lt;/em&gt;, a version of the project where AI agents are first-class participants, not afterthoughts bolted on from the outside.&lt;/p&gt;

&lt;p&gt;The fragments are out there. Time to find them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Seed4j is an open-source application generator. The MCP server is available at &lt;a href="https://github.com/avdev4j/seed4j-mcp" rel="noopener noreferrer"&gt;github.com/avdev4j/seed4j-mcp&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Let Your AI Agent Scaffold Apps With seed4j-mcp</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Mon, 18 May 2026 20:51:07 +0000</pubDate>
      <link>https://dev.to/avdev4j/let-your-ai-agent-scaffold-apps-with-seed4j-mcp-344l</link>
      <guid>https://dev.to/avdev4j/let-your-ai-agent-scaffold-apps-with-seed4j-mcp-344l</guid>
      <description>&lt;p&gt;If you've ever bootstrapped a Spring Boot + Vue project by hand, you know the routine: pick a build tool, glue in a frontend, add JPA, choose a database driver, wire Liquibase, remember the Maven wrapper, look up that one annotation for the seventh time this year. By the time you reach &lt;code&gt;initial commit&lt;/code&gt;, half your motivation is gone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/seed4j" rel="noopener noreferrer"&gt;seed4j&lt;/a&gt; already solves most of that. It's an open source application generator that applies &lt;em&gt;modules&lt;/em&gt; to a project folder — click click click, project done.&lt;/p&gt;

&lt;p&gt;But seed4j is still a tool &lt;strong&gt;a human drives&lt;/strong&gt;. You read the docs, you pick the module slugs, you remember whether the property is &lt;code&gt;packageName&lt;/code&gt; or &lt;code&gt;basePackage&lt;/code&gt; this release. Fine, but not exactly thrilling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/avdev4j/seed4j-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;seed4j-mcp&lt;/code&gt;&lt;/a&gt; is a &lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; server that hands seed4j to your AI agent instead. Plug it into Claude Code, Claude Desktop, or Cursor, and the agent can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;browse the seed4j catalog,&lt;/li&gt;
&lt;li&gt;pick a coherent stack,&lt;/li&gt;
&lt;li&gt;validate properties before applying anything,&lt;/li&gt;
&lt;li&gt;and scaffold a project end to end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You stay in the conversation. The agent does the orchestration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heads up — this is an alpha.&lt;/strong&gt; &lt;code&gt;seed4j-mcp&lt;/code&gt; is a fresh first release. The tool surface, defaults, and behavior may change as feedback comes in. It's stable enough to play with, but don't wire it into anything critical yet. Bug reports and suggestions are very welcome.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  How the pieces fit together
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;seed4j-mcp&lt;/code&gt; is intentionally thin. Three components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A running seed4j instance&lt;/strong&gt; — the actual generator, reachable over HTTP (default &lt;code&gt;http://localhost:1339&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;seed4j-mcp&lt;/code&gt;&lt;/strong&gt; — a Node.js MCP server that translates MCP tool calls into seed4j REST calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your MCP client&lt;/strong&gt; — Claude Code, Claude Desktop, Cursor, etc., speaking MCP over STDIO to &lt;code&gt;seed4j-mcp&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Claude Code] ⇄ STDIO ⇄ [seed4j-mcp] ⇄ HTTP ⇄ [seed4j server]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That separation matters: &lt;code&gt;seed4j-mcp&lt;/code&gt; does not embed seed4j as a library. It's a translator. seed4j can evolve on its own and the MCP server keeps doing its job — no version-pinning gymnastics.&lt;/p&gt;

&lt;p&gt;One implementation detail worth knowing: &lt;code&gt;seed4j-mcp&lt;/code&gt; speaks MCP over &lt;strong&gt;STDIO&lt;/strong&gt;. The MCP framing lives on stdout, which means anything else writing to stdout will corrupt the stream and your MCP client will hang. The server routes its startup errors to stderr for that reason. If you fork the project and add logging, use &lt;code&gt;console.error&lt;/code&gt; or write to a file — never &lt;code&gt;console.log&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tutorial
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Three things on your machine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js 20+&lt;/strong&gt; — &lt;code&gt;seed4j-mcp&lt;/code&gt; ships as an npm package and runs under Node (yes, even if you're a Java person).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A running seed4j instance&lt;/strong&gt; — see the &lt;a href="https://github.com/seed4j" rel="noopener noreferrer"&gt;seed4j docs&lt;/a&gt; for how to start one. Default URL: &lt;code&gt;http://localhost:1339&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An MCP-aware client&lt;/strong&gt; — I'll use &lt;a href="https://claude.com/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, but Claude Desktop and Cursor work the same way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick sanity checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;            &lt;span class="c"&gt;# v20.x or newer&lt;/span&gt;
curl http://localhost:1339/api/modules | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the curl call returns JSON, you're ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;You don't need to install &lt;code&gt;seed4j-mcp&lt;/code&gt; globally. The package is published on npm and the recommended pattern is to let your MCP client launch it on demand via &lt;code&gt;npx&lt;/code&gt;. First run pulls it down, later runs use the cache.&lt;/p&gt;

&lt;p&gt;If you'd rather install it globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; seed4j-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or build from source if you want to contribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/avdev4j/seed4j-mcp.git
&lt;span class="nb"&gt;cd &lt;/span&gt;seed4j-mcp
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run it with Claude Code
&lt;/h3&gt;

&lt;p&gt;Claude Code has an &lt;code&gt;mcp&lt;/code&gt; subcommand built for exactly this. Pick a scope based on how widely you want the server available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Local: just you, this project (default scope)&lt;/span&gt;
claude mcp add seed4j &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; seed4j-mcp

&lt;span class="c"&gt;# Project: committed to .mcp.json, shared with collaborators&lt;/span&gt;
claude mcp add seed4j &lt;span class="nt"&gt;--scope&lt;/span&gt; project &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; seed4j-mcp

&lt;span class="c"&gt;# User: available across all your projects on this machine&lt;/span&gt;
claude mcp add seed4j &lt;span class="nt"&gt;--scope&lt;/span&gt; user &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; seed4j-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running seed4j on a non-default URL? Pass it as an env var:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add seed4j &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;SEED4J_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:7471 &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; seed4j-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the server is wired up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Code and the tools become available to the agent automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run it with Claude Desktop or Cursor
&lt;/h3&gt;

&lt;p&gt;Both clients read a JSON config. Add an entry pointing at the npx entrypoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"seed4j"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"seed4j-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"SEED4J_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:1339"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the client and you're done.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example usages
&lt;/h2&gt;

&lt;p&gt;The real test is what the agent does once the tools are available. A few prompts that exercise different flows.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. "Scaffold a Spring Boot + Vue webapp"
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;curated stack&lt;/strong&gt; path. You name the vibe, the agent picks a preset. Under the hood it will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;code&gt;list_presets&lt;/code&gt; to see what's on offer.&lt;/li&gt;
&lt;li&gt;Pick the one that matches (e.g. &lt;em&gt;"Webapp: Vue + Spring Boot"&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;get_preset_details&lt;/code&gt; for the ordered module list.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;create_project&lt;/code&gt; to initialize the folder.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;apply_preset&lt;/code&gt; to apply every module in order with a shared property map.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your prompt is one line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Scaffold a new project at &lt;code&gt;/tmp/my-webapp&lt;/code&gt; using a Vue + Spring Boot preset. Use &lt;code&gt;com.example.webapp&lt;/code&gt; as the Java package and &lt;code&gt;mywebapp&lt;/code&gt; as the base name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. "I want a custom stack, not a preset"
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;custom stack&lt;/strong&gt; path. The agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;search_modules&lt;/code&gt; to find candidates matching your description.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_module_dependencies&lt;/code&gt; to learn the prerequisite ordering and any feature choices (yes, you have to pick a datasource flavor — the agent won't guess for you).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;validate_properties&lt;/code&gt; to dry-run the property map before touching the filesystem.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apply_modules&lt;/code&gt; to apply the full ordered list in one batch, stopping at the first failure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create a Java library project at &lt;code&gt;/tmp/my-lib&lt;/code&gt; with Maven, Jacoco, and SonarQube wired up. Package &lt;code&gt;com.example.lib&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. "What's already in this project?"
&lt;/h3&gt;

&lt;p&gt;When the folder exists, &lt;code&gt;get_project_status&lt;/code&gt; tells the agent which modules have been applied and what properties are in play — so it suggests sensible next steps instead of stomping over existing state:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Look at &lt;code&gt;/tmp/my-webapp&lt;/code&gt; and tell me what's wired up. What would you suggest adding next?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4. "Show me the catalog"
&lt;/h3&gt;

&lt;p&gt;You can also use the agent as a guided browser. It will reach for &lt;code&gt;search_modules&lt;/code&gt; and &lt;code&gt;get_module_details&lt;/code&gt; and summarize the catalog:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What persistence modules does seed4j support? Compare Postgres, MySQL, and MongoDB options.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Available tools
&lt;/h2&gt;

&lt;p&gt;The agent gets a small but expressive toolbox covering module discovery, preset lookup, property validation, and project application. Rather than reproducing the full list here (and watching it drift the next time a tool is added), check the up-to-date catalog directly in the repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/avdev4j/seed4j-mcp#tools-exposed-to-the-agent" rel="noopener noreferrer"&gt;&lt;strong&gt;github.com/avdev4j/seed4j-mcp&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The README lists every tool with the description the agent actually sees.&lt;/p&gt;




&lt;h2&gt;
  
  
  See it in action
&lt;/h2&gt;

&lt;p&gt;If you'd like to see what a project scaffolded through &lt;code&gt;seed4j-mcp&lt;/code&gt; actually looks like, here's one I generated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/avdev4j/seed4j-mcp-sample-app" rel="noopener noreferrer"&gt;&lt;strong&gt;avdev4j/seed4j-mcp-sample-app&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's the output of a real agent session — useful as a reference for the kind of structure, files, and module combination you can expect when you hand the wheel to your AI agent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Application generators have always traded flexibility for speed: faster than handcrafting, less flexible than writing it yourself. Putting an LLM in front of one tips the balance — the agent handles orchestration, and you stay at the level of &lt;em&gt;"build me a Java library with Jacoco and SonarQube"&lt;/em&gt;. No memorizing slugs, no fighting property names.&lt;/p&gt;

&lt;p&gt;And the scaffolded project isn't a dead drop. seed4j writes a &lt;code&gt;documentation/&lt;/code&gt; folder alongside the code with the conventions, code style, and recommendations specific to the modules you applied. That folder is a goldmine for the &lt;em&gt;next&lt;/em&gt; step: pointing your AI agent at it while you write the business code keeps the generated structure and the hand-written code coherent — same package layout, same patterns, same style — instead of the usual drift between bootstrapped scaffolding and the features you add on top.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;seed4j-mcp&lt;/code&gt; is Apache 2.0. Source at &lt;a href="https://github.com/avdev4j/seed4j-mcp" rel="noopener noreferrer"&gt;github.com/avdev4j/seed4j-mcp&lt;/a&gt;, published on npm as &lt;a href="https://www.npmjs.com/package/seed4j-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;seed4j-mcp&lt;/code&gt;&lt;/a&gt;. Issues, PRs, and creative stack requests welcome.&lt;/p&gt;

&lt;p&gt;If you ship something with it, I'd love to see it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>claude</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Composable Apps security practices with Entando on Kubernetes, featuring Ippon expert</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Fri, 27 Jan 2023 14:23:36 +0000</pubDate>
      <link>https://dev.to/entando/composable-apps-security-practices-with-entando-on-kubernetes-featuring-ippon-expert-59ie</link>
      <guid>https://dev.to/entando/composable-apps-security-practices-with-entando-on-kubernetes-featuring-ippon-expert-59ie</guid>
      <description>&lt;p&gt;Building composable apps means, without a doubt, understanding how it manages security and reliability. Composable apps offer a lot of advantages to streamline applications, provided by the modularity and reusability of Packaged Business Capabilities. Individual modules and PBCs help isolate problems and security design, separate frontend and backend concerns and allow patching at the component level. At the company level, and with a good hub policy, it turns into “patch once, secure all” because you can easily leverage security fixes if they are applied to centralized modules in a store that all your applications rely on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxe5vsik1urbj9jmh3gx0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxe5vsik1urbj9jmh3gx0.png" alt=" " width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, security strategies should not be applied at the code or module level only. The infrastructure has to be fully resilient and secure. No one can imagine using a car with seat belts within an insecure chassis. It doesn't make sense. Security is everyone’s business.&lt;/p&gt;

&lt;p&gt;Fortunately, solutions exist to help us design at all levels with security as one of the top priorities.&lt;/p&gt;

&lt;p&gt;"Shift security left". It is more than a buzzword, It is good advice according to Lucas Ward in a recent article called &lt;a href="https://blog.ippon.tech/hardening-kubernetes-and-what-that-entails-with-entando/" rel="noopener noreferrer"&gt;Hardening Kubernetes and What That Entails With Entando&lt;/a&gt;&lt;span&gt;.&lt;/span&gt; There, Ward describes how building applications with Kubernetes is challenging.&lt;/p&gt;

&lt;p&gt;I agree, building a fully secured application with Kubernetes is a real adventure. If there is something we can't live without, it is security. Whatever business domain we work in, security should be at the center of the design and production processes.&lt;/p&gt;

&lt;p&gt;Delaying its implementation is risky; executing it is time consuming.&lt;/p&gt;

&lt;p&gt;As Ward spells out, we can rely on frameworks to bring a smooth and dependable way to secure applications, especially with Kubernetes. He says that using a platform such as Entando provides simplicity and a solid base with best practices you can count on to promote security from the ground up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kp9j572o9nd9xzg72mb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9kp9j572o9nd9xzg72mb.png" alt=" " width="761" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From solid structures and base setup with code generation to a well documented CI/CD process, and opinionated build pipelines, Ward asserts that "using Entando as your platform of choice covers a lot of ground in the Development, Build, and Infrastructure scape."&lt;/p&gt;

&lt;p&gt;Saying more without spoiling it is just impossible, just read it! This is my only advice.&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>bitcoin</category>
      <category>blockchain</category>
      <category>web3</category>
    </item>
    <item>
      <title>Explore Docker-based bundles with JHipster and Entando 7.1</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Tue, 10 Jan 2023 10:08:27 +0000</pubDate>
      <link>https://dev.to/entando/explore-docker-based-bundles-with-jhipster-and-entando-71-1b84</link>
      <guid>https://dev.to/entando/explore-docker-based-bundles-with-jhipster-and-entando-71-1b84</guid>
      <description>&lt;p&gt;At Entando we define a bundle as a package that contains one or more components. A bundle can be a single component, component collection, PBC, or  solution template, based on the level of granularity. Any bundle built with Entando is an Entando Bundle.&lt;/p&gt;

&lt;p&gt;Entando 7.1 introduces a major new change for bundles with a Docker-based structure. This article explores all the things you need to know about that feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  A shift from Git-based bundles
&lt;/h2&gt;

&lt;p&gt;If you’ve already built or used bundles with Entando, you should know that before v7.1, the bundles were Git-based. That means the source code (called project) and the built artifact (the deployable bundle) were stored under two different Git repositories.&lt;/p&gt;

&lt;p&gt;Traditionally, the source code repository is used by the Creators team for coding and building components with development tooling. The coding flow is similar to what we find in any development team, pushing and merging branches to share and review the code within the team.&lt;/p&gt;

&lt;p&gt;The second repository stores the result of the compiling process, the artifact, that Curators can register in a hub, and Composers can install on their Application Composition Platform.&lt;/p&gt;

&lt;p&gt;The Docker-based bundle is a total shift from that point. The source repository is still present but, all the artifacts are now sent to a Docker registry using Docker images.&lt;/p&gt;

&lt;h2&gt;
  
  
  A structure modification
&lt;/h2&gt;

&lt;p&gt;The publishing process was improved with the tool change, so we took the opportunity to streamline the bundle structure itself.&lt;/p&gt;

&lt;p&gt;We have a more readable and consistent bunch of folders with the Docker-based bundles.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
   &lt;td&gt;
&lt;strong&gt;Git-based&lt;/strong&gt;
   &lt;/td&gt;
   &lt;td&gt;
&lt;strong&gt;Docker-based&lt;/strong&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;
&lt;em&gt;bundle/descriptor.yaml&lt;/em&gt;
&lt;p&gt;
The main bundle descriptor
   &lt;/p&gt;
&lt;/td&gt;
   &lt;td&gt;
&lt;em&gt;entando.json&lt;/em&gt;
&lt;p&gt;
The main Entando file that contains components definition and metadata
   &lt;/p&gt;
&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;
&lt;em&gt;ui/&lt;/em&gt;
&lt;p&gt;
The micro frontends sources folder
   &lt;/p&gt;
&lt;/td&gt;
   &lt;td&gt;
&lt;em&gt;microfrontends/&lt;/em&gt;
&lt;p&gt;
Centralized micro frontends folder
   &lt;/p&gt;
&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;src/
&lt;p&gt;
The backend sources folder
   &lt;/p&gt;
&lt;/td&gt;
   &lt;td&gt;
&lt;em&gt;microservices/&lt;/em&gt;
&lt;p&gt;
The microservices folder, one per component
   &lt;/p&gt;
&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;
&lt;em&gt;src/main/docker&lt;/em&gt;
&lt;p&gt;
The auxiliary service folder such as Docker compose files and Keycloack configuration for local usages 
   &lt;/p&gt;
&lt;/td&gt;
   &lt;td&gt;
&lt;em&gt;svc/&lt;/em&gt;
&lt;p&gt;
The auxiliary service folder such as Dockercompose files and Keycloack configuration for local usage 
   &lt;/p&gt;
&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;
&lt;em&gt;*.sh&lt;/em&gt;
&lt;p&gt;
Shell script used by the CLI to compile and build the bundle
   &lt;/p&gt;
&lt;/td&gt;
   &lt;td&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;
   &lt;/td&gt;
   &lt;td&gt;
&lt;em&gt;platform/&lt;/em&gt;
&lt;p&gt;
The folder for any Entando related component such as pages, content, page templates… One sub-folder per component type
   &lt;/p&gt;
&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you like to make a deep comparison between these implementations, our documentation provides a table &lt;a href="https://developer.entando.com/v7.1/docs/curate/bundle-comparison.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This means that the cli and commands are now following that structure and you can easily run them to create a new one.&lt;/p&gt;

&lt;p&gt;Let’s start a new project to discover this&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a new 7.1 bundle with the ent CLI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before moving forward, you have to ensure that your Entando CLI is up to date. If not, please run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-sfL&lt;/span&gt; https://get.entando.org/cli&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzycu0g7mnphlqe4hcs2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzycu0g7mnphlqe4hcs2j.png" alt=" " width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don’t forget to activate it with the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.entando/activate"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialize the project
&lt;/h3&gt;

&lt;p&gt;From your favorite folder, run the following command to initialize the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ent bundle init my-bundle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Please note you can replace “my-bundle” according to your project name.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A new folder is created with this project name; open it as a project with your favorite IDE to check the new structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9cqatuypfimzejk3rsx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9cqatuypfimzejk3rsx.png" alt=" " width="800" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check the entando.json file content, and the metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"microservices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"microfrontends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"svc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-bundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-bundle description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundle"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add a microservice
&lt;/h3&gt;

&lt;p&gt;In the project folder, run the following command to add a new microservice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ent bundle ms add sample-ms &lt;span class="nt"&gt;--stack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;spring-boot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We specify the stack because of the dedicated metadata we may need with some stack types.  This command creates a new folder, sample-ms, in microservices and adds an entry in the entando.json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"microservices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sample-ms"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"stack"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"spring-boot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"healthCheckPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/health"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"microfrontends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"svc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-bundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-bundle description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundle"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note this new folder is empty and you have to add your own code. We provide an easy way to start; let’s do it with JHipster.&lt;/p&gt;

&lt;p&gt;Call JHipster with the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;microservices/sample-ms
ent jhipster &lt;span class="nt"&gt;--blueprints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;entando
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, select only the default values.&lt;/p&gt;

&lt;p&gt;When the generation is done, the sample-ms folder contains all the files provided by JHipster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize the bundle for JHipster
&lt;/h3&gt;

&lt;p&gt;You just need to tweak a couple of things to make it work properly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edit the &lt;code&gt;entando.json&lt;/code&gt; and update &lt;code&gt;microservices/sample-ms&lt;/code&gt; to set the &lt;code&gt;healthCheckPath&lt;/code&gt; and &lt;code&gt;dbms&lt;/code&gt; properties:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nl"&gt;"healthCheckPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/management/health"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"dbms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"postgresql"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Move the Blueprint-provided auxiliary service definitions into the svc directory in the bundle project:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;microservices/sample-ms/src/main/docker/&lt;span class="k"&gt;*&lt;/span&gt; svc/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This enables the ent CLI to start Keycloak:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ent bundle svc &lt;span class="nb"&gt;enable &lt;/span&gt;keycloak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For advanced use cases, you can add MFEs with &lt;a href="https://developer.entando.com/v7.1/tutorials/create/ms/generate-microservices-and-micro-frontends.html#generate-the-components" rel="noopener noreferrer"&gt;this tutorial&lt;/a&gt;. Please note that for microservices, you have to execute some extra steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discover the new publishing process
&lt;/h2&gt;

&lt;p&gt;This new bundle structure comes with a simpler publishing process provided by new streamlined CLI commands.&lt;/p&gt;

&lt;p&gt;You can find a graphic of the different steps below. It describes the overall process and helps you to understand the details involved in every step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfjs9mmnrhh6sdi88b7q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmfjs9mmnrhh6sdi88b7q.png" alt=" " width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's follow it for our new 7.1 bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build
&lt;/h3&gt;

&lt;p&gt;From the root project folder, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ent bundle pack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note, you need to have Maven &lt;a href="https://maven.apache.org/install.html" rel="noopener noreferrer"&gt;installed&lt;/a&gt; for this to execute. You also need Docker installed; you can check the installation procedure &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;here&lt;/a&gt; regarding your environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5uurcnn91volsdp18xd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz5uurcnn91volsdp18xd.png" alt=" " width="402" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can run the &lt;code&gt;docker image ls&lt;/code&gt; command to see your available images.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2fllebr6hfvohmotby5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2fllebr6hfvohmotby5e.png" alt=" " width="800" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Publish
&lt;/h3&gt;

&lt;p&gt;Once it’s finished, run the next command to publish the bundle to a Docker repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ent bundle publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this step, you need to be logged into the Docker hub, ensure you have an account or create a new one on this website: &lt;a href="https://hub.docker.com" rel="noopener noreferrer"&gt;https://hub.docker.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;_Please note, you can decide to publish the images to another registry by providing the URL with the &lt;code&gt;--registry&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwmnqjsavezzlf9siirr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwmnqjsavezzlf9siirr.jpg" alt=" " width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk64bmnd6vc3rp9q70w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwk64bmnd6vc3rp9q70w6.png" alt=" " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy
&lt;/h3&gt;

&lt;p&gt;This step is the same as the previous Entando version, even if the commands have been modified to keep the consistency. Here, you need to have an available running instance of Entando. Visit &lt;a href="https://developer.entando.com" rel="noopener noreferrer"&gt;https://developer.entando.com&lt;/a&gt; to install a local one.&lt;/p&gt;

&lt;p&gt;Please note that you need your ent CLI profile to be connected to your Entando instance. If you followed the previous steps and installed a local multipass VM, you might have to run this command:&lt;code&gt;ent attach-vm entando&lt;/code&gt; where “entando” is the virtual machine name.&lt;/p&gt;

&lt;p&gt;Otherwise, it is possible to attach a kubeconfig file with this: &lt;code&gt;ent attach-kubeconfig {kubeconfig-file}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From your bundle root folder, run the following command:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08d5bi4tjfcpfo1333xm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F08d5bi4tjfcpfo1333xm.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the deploying process is finished, you can navigate to your Local Hub by clicking on the “Hub” menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo0ffjy23t87r8hnctmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo0ffjy23t87r8hnctmz.png" alt=" " width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, you should see your bundle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7z51mj5eb0dgqoh4qh30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7z51mj5eb0dgqoh4qh30.png" alt=" " width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;As you can see, the bundle is available in your Local Hub but not installed yet. That means nothing is running on your cluster from that bundle and the components are not available for composition.&lt;/p&gt;

&lt;p&gt;To install them, you can use the UI and click on the install button in the Local Hub or, you can run the following command from your bundle root folder: &lt;code&gt;ent bundle install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mg9fbb3367wpwippdhz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6mg9fbb3367wpwippdhz.png" alt=" " width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The micro frontends are now available in the App Builder to compose new pages. the microservices as pods and you can check them with &lt;code&gt;ent kubectl get pods -n entando.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we discovered a few new features provided by Entando 7.1. The bundle structure has been rebuilt; they are now docker-based and the publishing process has been optimized with the ent CLI commands. The JHipster blueprint has been optimized to match this new paradigm.&lt;/p&gt;

&lt;p&gt;You can find explanations of these features during our &lt;a href="https://youtu.be/GoxX-N15ZGk" rel="noopener noreferrer"&gt;7.1 live with Sohini&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Did you know the bundle we just created can be used like a template to create a new one? Maybe not, because it’s also a new feature on 7.1 and this is the topic of the next blog post in this series. Stay tuned.&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
    <item>
      <title>Using Vue.js to create a Micro Frontend</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Mon, 27 Jun 2022 13:15:56 +0000</pubDate>
      <link>https://dev.to/entando/using-vuejs-to-create-a-micro-frontend-4815</link>
      <guid>https://dev.to/entando/using-vuejs-to-create-a-micro-frontend-4815</guid>
      <description>&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article has been written with the help of the ModSquad Community. The related live session is available here:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/VDj6LVRwsEM"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hi, fellow developers!&lt;/p&gt;

&lt;p&gt;After learning how to create micro frontends with Angular and React, we’re jumping into another world with Vue.js. Remember, we’re trying to create a micro frontend using the web component specifications for each of the following frameworks: Angular, React, and Vue.js.&lt;/p&gt;

&lt;p&gt;Does Vue provide the best developer experience when creating a micro frontend social card? Let’s try it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Vue.js app
&lt;/h2&gt;

&lt;p&gt;First, ensure that you have installed Node with npm (you can use Yarn instead) and Vue CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @vue/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can create the application by running the following command in your target folder. I suggest using the default option &lt;code&gt;Default ([Vue 3] babel, eslint)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vue create vue-social-card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should create a folder named &lt;code&gt;vue-social-card&lt;/code&gt; that contains a fresh Vue.js project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqijl14hqttgdbml3dk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqijl14hqttgdbml3dk9.png" alt=" " width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that by default the application is configured to include certain features, such as npm scripts to start your app and eslint to help you code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discover your application
&lt;/h2&gt;

&lt;p&gt;Before making any changes and creating a micro frontend, let’s run the application locally using the command &lt;code&gt;npm run serve&lt;/code&gt;. Your application should then be available at the following URL: &lt;a href="http://localhost:8080/" rel="noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbh5ct6adqb5qr7rv21p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbh5ct6adqb5qr7rv21p.png" alt=" " width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the social card component
&lt;/h2&gt;

&lt;p&gt;Vue.js helps you organize yourcode with components. That means we need to create a file to contain all the card code. You can delete the default file called &lt;code&gt;HelloWorld.vue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you’ve created a new file named &lt;code&gt;SocialCard.vue&lt;/code&gt; in the components folder, copy the following code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;{{ card.name }}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ card.description }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;:src=&lt;/span&gt;&lt;span class="s"&gt;"card.image"&lt;/span&gt; &lt;span class="na"&gt;:alt=&lt;/span&gt;&lt;span class="s"&gt;"card.image_alt"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;320px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;450px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;68&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.01&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.19&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;.title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our component is just a simple piece of HTML/CSS code that requires an entry object named &lt;code&gt;card&lt;/code&gt; and defines the following properties: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt; and &lt;code&gt;image_alt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As it is, your application might be broken due to an error in the &lt;code&gt;app.vue&lt;/code&gt; file. It’s time to update it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update App.vue
&lt;/h2&gt;

&lt;p&gt;The reason your app doesn’t work is that the main component still includes the default component. To fix it, replace the file contents with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SocialCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/SocialCard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;SocialCard&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;shiba_card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shiba Inu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;      A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;      bred for hunting.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://material.angular.io/assets/img/examples/shiba2.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;image_alt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The Shiba Inu image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;SocialCard&lt;/span&gt; &lt;span class="na"&gt;:card=&lt;/span&gt;&lt;span class="s"&gt;shiba_card&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/SocialCard&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This imports our social card component, defines a card object &lt;code&gt;shiba_card&lt;/code&gt; in the &lt;code&gt;data()&lt;/code&gt; function to store the different properties, then passes the card object to the social card component in the &lt;code&gt;template&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;The application is working again and the default Vue landing page is replaced with the Shiba Inu social card.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx0iepwz4d9yhdcld4s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx0iepwz4d9yhdcld4s0.png" alt=" " width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, we only built a classic single page application and need to migrate it to a micro frontend. &lt;/p&gt;

&lt;h2&gt;
  
  
  Define the custom element
&lt;/h2&gt;

&lt;p&gt;In order to reuse this app as a web component, we need to define a custom element, which is a typical step we discovered when using Angular and React.&lt;/p&gt;

&lt;p&gt;Replace the content of the main.js file with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineCustomElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SocialCardElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineCustomElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;social-card-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SocialCardElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code defines the &lt;code&gt;social-card-element&lt;/code&gt; custom element and wraps the Vue app. As we saw before, this app is now rendering the card as expected.&lt;/p&gt;

&lt;p&gt;Next, replace &lt;code&gt;&amp;lt;&lt;strong&gt;div&lt;/strong&gt; id="app"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; in the &lt;code&gt;public/index.html&lt;/code&gt; file with the custom element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;We're sorry but &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;htmlWebpackPlugin.options.title&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; doesn't work properly without JavaScript enabled. Please enable it to continue.&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;social-card-element&amp;gt;&amp;lt;/social-card-element&amp;gt;&lt;/span&gt;
 &lt;span class="c"&gt;&amp;lt;!-- built files will be auto injected --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Congratulations! You have just built a Vue.js micro frontend using a custom element.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please note, as I’m writing this article there is an issue with styling and custom elements that is discussed in detail here: &lt;a href="https://github.com/vuejs/core/issues/4662" rel="noopener noreferrer"&gt;https://github.com/vuejs/core/issues/4662&lt;/a&gt;. Please follow this ticket to know when it will be fixed or for current workarounds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;The code above is available on GitHub: &lt;a href="https://github.com/avdev4j/vue-social-card" rel="noopener noreferrer"&gt;https://github.com/avdev4j/vue-social-card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to this repo for the card example: &lt;a href="https://github.com/AlanPenaRuiz/vue-rick-and-morty" rel="noopener noreferrer"&gt;https://github.com/AlanPenaRuiz/vue-rick-and-morty&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you already using Entando and looking for Vue.js components? Take a look at this sample: &lt;a href="https://github.com/entando-samples/ent-project-template-vue" rel="noopener noreferrer"&gt;https://github.com/entando-samples/ent-project-template-vue&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Watch micro frontend videos on our YouTube channel: &lt;a href="https://www.youtube.com/c/EntandoVideos" rel="noopener noreferrer"&gt;https://www.youtube.com/c/EntandoVideos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Join us on Discord to share and learn about composable apps: &lt;a href="https://discord.gg/SdMCvyzzHm" rel="noopener noreferrer"&gt;https://discord.gg/SdMCvyzzHm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>microfrontend</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Using React to create a Micro Frontend</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Mon, 20 Jun 2022 09:26:06 +0000</pubDate>
      <link>https://dev.to/entando/using-react-to-create-a-micro-frontend-4jn2</link>
      <guid>https://dev.to/entando/using-react-to-create-a-micro-frontend-4jn2</guid>
      <description>&lt;h2&gt;
  
  
  Disclaimer
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article has been written with the help of the ModSquad Community. The related live session is available here:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/4sF3XYlNZC4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hi, fellow developers!&lt;/p&gt;

&lt;p&gt;Having discovered micro frontend creation with Angular, we jump into another world with React. Remember, I’m trying to create a micro frontend using the web component specifications foreach of the following frameworks: Angular, React, and Vue.js.&lt;/p&gt;

&lt;p&gt;Does React provide the best developer experience when creating a micro frontend social card? Let’s try it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the React app
&lt;/h2&gt;

&lt;p&gt;React offers a simple way to &lt;a href="https://github.com/facebook/create-react-app" rel="noopener noreferrer"&gt;create React applications&lt;/a&gt; using the &lt;a href="https://create-react-app.dev/docs/getting-started/" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As seen in the previous blog, you need to have npm installed. You can then run the following command to create the application skeleton:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app react-social-card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once complete, you should have a new React project available in the &lt;code&gt;react-social-card&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Start it using the command &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The default React page is reachable at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjdl4jlg2idiq9gftnp7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjdl4jlg2idiq9gftnp7.png" alt=" " width="800" height="534"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Add the social card code
&lt;/h2&gt;

&lt;p&gt;Before configuring the &lt;code&gt;custom-element&lt;/code&gt;, we have to create the React social card component. After some research, here is an example of code we can use: &lt;a href="https://codepen.io/leoraw/pen/ZjvRpL" rel="noopener noreferrer"&gt;https://codepen.io/leoraw/pen/ZjvRpL&lt;/a&gt;. Thanks to &lt;a href="https://codepen.io/leoraw" rel="noopener noreferrer"&gt;@leoraw&lt;/a&gt; for sharing this example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the React components
&lt;/h3&gt;

&lt;p&gt;The social card is split into two different React components: a button box and the card itself.&lt;/p&gt;

&lt;p&gt;First, we create a new file for the button box in the &lt;code&gt;components&lt;/code&gt; folder, name it &lt;code&gt;ButtonBox.js&lt;/code&gt; and copy this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UiButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui-button clicked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui-button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ui-icon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ButtonBox&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;likeIsClicked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;

     &lt;span class="p"&gt;};&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
     &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
     &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UiButton&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;♥&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;likes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
           &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
             &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;likeIsClicked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
           &lt;span class="nx"&gt;isClicked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;ButtonBox&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in the same folder, we create the &lt;code&gt;SocialCard.js&lt;/code&gt; file and copy the following content.&lt;/p&gt;

&lt;p&gt;Please note that this new component imports and use the previous one. Effectively, the internal architecture in the micro frontend allows us to use multiple components, and all the components are built into one custom element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ButtonBox&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./ButtonBox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UiCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card-wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SocialCard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UiCard&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;line&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ButtonBox&lt;/span&gt;
             &lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
             &lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
     &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;SocialCard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use the new components in the main App.js file
&lt;/h3&gt;

&lt;p&gt;Once these two components are available, we can update the main &lt;code&gt;App.js&lt;/code&gt; file and remove the old React demo code.&lt;/p&gt;

&lt;p&gt;Update the &lt;code&gt;App.js&lt;/code&gt; file by replacing the existing code with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SocialCard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./components/SocialCard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cardDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shiba Inu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://material.angular.io/assets/img/examples/shiba2.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan. A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally bred for hunting.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="na"&gt;likeIsClicked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SocialCard&lt;/span&gt;
     &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cardDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cardDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cardDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;cardDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;likeIsClicked&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see here that we are instantiating a new social card component and giving it some data to display.&lt;/p&gt;

&lt;p&gt;Now you can restart the application or refresh the page to see our social card appear. However, this is still a raw React application and we need to define the &lt;code&gt;custom-element&lt;/code&gt; to finish our task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhdl863euijt55n7qryw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhhdl863euijt55n7qryw.png" alt=" " width="487" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Switch the app to a custom element
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; folder, at the same level as the &lt;code&gt;components&lt;/code&gt; folder, we create a new folder named &lt;code&gt;custom-element&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, let’s create a new file named &lt;code&gt;social-card-app.js&lt;/code&gt; to define the &lt;code&gt;custom-element&lt;/code&gt; using the related API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SocialCardApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mountPoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;span&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/React.StrictMode&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;           &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mountPoint&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-social-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-social-card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SocialCardApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The string “react-social-card” is used to define the &lt;code&gt;custom-element&lt;/code&gt; tag and renders the React app using: &lt;code&gt;&amp;amp;lt;App/&amp;gt;.&lt;/code&gt;It’s analogous to Russian dolls: &lt;code&gt;custom-element &amp;gt; React app &amp;gt; social card component &amp;gt; buttonbox component.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, in the file &lt;code&gt;index.js&lt;/code&gt; import the custom-element and replace all the previous content with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import './custom-element/social-card-app';
```



Then, in the following `public/index.html` file, replace the body with this:




```html
&amp;lt;body&amp;gt;
 &amp;lt;noscript&amp;gt;You need to enable JavaScript to run this app.&amp;lt;/noscript&amp;gt;
 &amp;lt;react-social-card&amp;gt;&amp;lt;/react-social-card&amp;gt;
&amp;lt;/body&amp;gt;
```




Reload your browser and check the HTML content:



![ ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmajvoe2sxvzo4id2eoa.png) 


The `react-social-card` custom element is used and loads the React app content.

**Congratulations! You’ve just created your first micro frontend using React!**


## Resources:

The code above is available on GitHub: [https://github.com/avdev4j/react-social-card](https://github.com/avdev4j/react-social-card)

Watch micro frontend videos on our YouTube channel: [https://www.youtube.com/c/EntandoVideos](https://www.youtube.com/c/EntandoVideos)

Join us on Discord to share and learn about composable apps: [https://discord.gg/SdMCvyzzHm](https://discord.gg/SdMCvyzzHm)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>javascript</category>
      <category>microfrontend</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Angular to create a Micro Frontend</title>
      <dc:creator>Anthony Viard</dc:creator>
      <pubDate>Tue, 14 Jun 2022 12:10:59 +0000</pubDate>
      <link>https://dev.to/entando/using-angular-to-create-a-micro-frontend-5fci</link>
      <guid>https://dev.to/entando/using-angular-to-create-a-micro-frontend-5fci</guid>
      <description>&lt;h3&gt;
  
  
  Disclaimer
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This article has been written with the help of the ModSquad Community. The related live session is available here:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/EEmMI1dENoE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Web Components
&lt;/h2&gt;

&lt;p&gt;Web components are a set of technologies, a &lt;em&gt;meta- specification&lt;/em&gt;, with reusable isolated elements that make up a web application.&lt;/p&gt;

&lt;p&gt;Basically, Web Components need 4 specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Elements:&lt;/strong&gt; A set of Javascript APIs to define the components and their behaviors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow DOM:&lt;/strong&gt; A set of APIs to render the element into a dedicated and isolated DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML Templates:&lt;/strong&gt; Allows you to use &amp;lt;template&amp;gt; and &amp;lt;slot&amp;gt; tags to define a portion of HTML to reuse in which slots could be filled with variable content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ES Modules&lt;/strong&gt;: A specification to import and use Javascript Modules to create an agnostic modular approach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern Javascript frameworks offer some solutions to easily create a web component, using a custom element, leveraging all the framework features, and creating small business-oriented apps. This is what we call micro frontends.&lt;/p&gt;

&lt;p&gt;Let’s see how to proceed using Angular and let’s see how to create our first micro frontend.&lt;/p&gt;

&lt;p&gt;To continue, you need to have installed &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; (including npm) and the Angular CLI&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @angular/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initiate the Project
&lt;/h2&gt;

&lt;p&gt;Here we go. We are going to create our first web component using Angular. For this first exercise, let’s create a card to describe people in our community. We call it “social card”.&lt;/p&gt;

&lt;p&gt;With your favorite terminal, create a new Angular project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new social-card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create an Angular Component
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add Angular material&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because we want to use the Angular Material library to create our component, we need to add it as a dependency on our project. During the installation, I select the default values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular/material
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create the Material Card Component&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From the example section of the Card component, I choose to implement the “Card with multiple sections” one. &lt;a href="https://material.angular.io/components/card/examples" rel="noopener noreferrer"&gt;https://material.angular.io/components/card/examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, I create a new Angular component. Please note “components” here refer to the &lt;a href="https://angular.io/api/core/Component" rel="noopener noreferrer"&gt;Angular Component&lt;/a&gt;, not Web Components defined in the introduction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng generate component card
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Angular CLI automatically creates all the needed files and updates the different files to make the application work out of the box.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;src/app/card/&lt;/code&gt; folder, open the HTML file and copy the following code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;mat-card&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"example-card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;mat-card-header&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;mat-card-avatar&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"example-header-image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;mat-card-title&amp;gt;&lt;/span&gt;John Doe&lt;span class="nt"&gt;&amp;lt;/mat-card-title&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;mat-card-subtitle&amp;gt;&lt;/span&gt;Dev Adcovate&lt;span class="nt"&gt;&amp;lt;/mat-card-subtitle&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/mat-card-header&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;mat-card-image&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://material.angular.io/assets/img/examples/shiba2.jpg"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Photo of a Shiba Inu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;mat-card-content&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
       The Shiba Inu is the smallest of the six original and distinct spitz breeds of dog from Japan.
       A small, agile dog that copes very well with mountainous terrain, the Shiba Inu was originally
       bred for hunting.
     &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/mat-card-content&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;mat-card-actions&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;mat-button&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;LIKE&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
     &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;mat-button&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;SHARE&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/mat-card-actions&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;/mat-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, open the CSS file and copy the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.example-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="nc"&gt;.example-header-image&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;background-image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('https://material.angular.io/assets/img/examples/shiba1.jpg')&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;background-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Import Angular Material Modules in your App Module&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, open the &lt;code&gt;src/app/app.module.ts&lt;/code&gt; to import the &lt;code&gt;MatCardModule&lt;/code&gt; and the &lt;code&gt;MatButtonModule&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MatCardModule&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;MatButtonModule&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/material/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
 &lt;span class="nx"&gt;MatCardModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;MatButtonModule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run your application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Edit the &lt;code&gt;app.component.html&lt;/code&gt; file from the &lt;code&gt;src/app&lt;/code&gt; folder and replace the existing with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-card&amp;gt;&amp;lt;/app-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can start your application by running the following command at the project root level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnki33auo9odg6zwgex3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnki33auo9odg6zwgex3g.png" alt=" " width="642" height="615"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;So far, so good, but the following application is not yet a Web Component and we need to make some changes to transform it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transform the Application into a Web Component
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add Angular elements dependency&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Angular elements is the name in the Angular ecosystem for custom elements. This dependency allows us to easily create a custom element from our existing application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular/elements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update the app.module.ts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From the &lt;code&gt;src/app/app.module.ts&lt;/code&gt; file, update the constructor, call the &lt;code&gt;createCustomElement()&lt;/code&gt; method, and define the custom element tag, &lt;code&gt;ng-social-card&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createCustomElement&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/elements&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Injector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCustomElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;injector&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ng-social-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="nf"&gt;ngDoBootstrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove the AppComponent in the &lt;code&gt;bootstrap&lt;/code&gt; array. we don’t need it anymore and it could generate errors in the console log.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update the index.html&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open the src/.html file and change the content to use the custom-element instead of the initial value. \&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;ng-social-card&amp;gt;&amp;lt;/ng-social-card&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have now instantiated the application, using a custom element instead of the regular app-root tag.&lt;/p&gt;

&lt;p&gt;Start the application again using &lt;code&gt;ng serve&lt;/code&gt; and check that the application is still working.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build and Run Your Web Component
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build it!
&lt;/h3&gt;

&lt;p&gt;To build your component you have to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feng0ryjvwh0yjpr73pvs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feng0ryjvwh0yjpr73pvs.png" alt=" " width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;dist&lt;/code&gt; folder is now created containing an HTML file and all the Javascript and CSS files.&lt;/p&gt;

&lt;p&gt;If you open the &lt;code&gt;index.html&lt;/code&gt;, you can see it contains the custom elements previously defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;NgSocialCard&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;ng-social-card&amp;gt;&amp;lt;/ng-social-card&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"runtime.6ef72ee47cb5bc7a.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"polyfills.41cc36d27639541d.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"main.8609c098aeba9ec8.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run it!
&lt;/h3&gt;

&lt;p&gt;To run it, you can install serve through npm to start a lightweight web server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And from the dist/ng-social-card folder, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F94sppuvovadrvqo2huxh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F94sppuvovadrvqo2huxh.png" alt=" " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fik0xcy8zkzsvf462m5vt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fik0xcy8zkzsvf462m5vt.png" alt=" " width="449" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations! You’ve just created your first micro frontend using Angular.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;All the code is available at the repository: &lt;a href="https://github.com/avdev4j/ng-social-card" rel="noopener noreferrer"&gt;https://github.com/avdev4j/ng-social-card&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find more micro frontends videos on our YouTube channel: &lt;a href="https://www.youtube.com/c/EntandoVideos" rel="noopener noreferrer"&gt;https://www.youtube.com/c/EntandoVideos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Join us on Discord to share and learn about Composable apps: &lt;a href="https://discord.gg/SdMCvyzzHm" rel="noopener noreferrer"&gt;https://discord.gg/SdMCvyzzHm&lt;/a&gt;&lt;/p&gt;

</description>
      <category>microfrontend</category>
      <category>angular</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
