{"id":14,"date":"2026-06-06T21:48:28","date_gmt":"2026-06-06T21:48:28","guid":{"rendered":"https:\/\/softwareproduction.eu\/wordpress\/?p=14"},"modified":"2026-06-07T01:21:48","modified_gmt":"2026-06-07T01:21:48","slug":"nuxt-based-code-generation-the-gqlt-and-i18nt-modules","status":"publish","type":"post","link":"https:\/\/softwareproduction.eu\/?p=14","title":{"rendered":"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Seventh in a series about migrating from legacy architectures to a modern Nuxt 4 stack.<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Beyond External Generators<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The previous article discussed GraphQL code generation using external tools like <code>graphql-codegen<\/code>. Those tools are excellent for generating types and composables from <code>.graphql<\/code> files, but in a large enterprise application they break down in two important areas:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>GraphQL composables that need Nuxt-specific wrappers<\/strong> \u2014 auto-imports, <code>useAsyncData<\/code> integration, client selection, SSR payload handling  <\/li>\n<li><strong>Internationalization types<\/strong> \u2014 translation files are YAML\/JSON, not GraphQL, and there is no standard way to generate TypeScript types from translation structures.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Both gaps are closed by <strong>Nuxt modules that generate code at build time<\/strong> \u2014 code that is emitted into <code>.nuxt\/<\/code>, auto-imported, and fully type-checked in the IDE.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">GQLT \u2014 The GraphQL Toolkit Module<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">GQLT is a Nuxt module that watches <code>.graphql<\/code> files, parses them, and generates typed composables into <code>.nuxt\/gqlt\/<\/code>. These composables are registered as auto-imports \u2014 developers never write an import.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How It Works<\/h3>\n\n\n\n<pre class=\"mermaid\">flowchart TB\n  A[\"Developer saves&lt;br\/&gt;queries\/cms\/pageByPath.graphql\"] --&gt; B[\"GQLT Module&lt;br\/&gt;(build time \/ dev watcher)\"]\n\n  subgraph \"GQLT Module\"\n    B1[Parse .graphql file]\n    B2[Resolve types from schema introspection]\n    B3[Generate composable files]\n    B4[Register all three as auto-imports]\n  end\n\n  B --&gt; B1 --&gt; B2 --&gt; B3 --&gt; B4\n\n  subgraph \"Generated composables in .nuxt\/gqlt\/\"\n    C1[\"usePageByPathQuery.ts&lt;br\/&gt;(reactive, useAsyncData-based)\"]\n    C2[\"usePageByPathClient.ts&lt;br\/&gt;(imperative, manual execution)\"]\n    C3[\"usePageByPathEntry.ts&lt;br\/&gt;(CMS-specific: fetch-or-use)\"]\n  end\n\n  B3 --&gt; C1\n  B3 --&gt; C2\n  B3 --&gt; C3\n\n  C1 &amp; C2 &amp; C3 --&gt; D[\"Developer uses in component&lt;br\/&gt;const { data } = usePageByPathQuery({ path: route.path })&lt;br\/&gt;\/\/ no import needed, fully typed\"]<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The crucial difference from external generators: GQLT emits <strong>Nuxt-native composables<\/strong> that understand the runtime. The reactive composable wraps <code>useAsyncData<\/code> with the correct cache key, chooses the right GraphQL client (for example, CMS vs. backend vs. default), and handles SSR payload serialization.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Entry Composable Pattern<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The third generated file \u2014 <code>use*Entry.ts<\/code> \u2014 addresses a pattern common in CMS-driven or catalog-driven applications. A page-level query retrieves a collection of content entries or products, and a child component needs just one entry. Without the entry composable, the child must either:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Re-fetch the entire collection (wasteful)<\/li>\n<li>Accept the entry via props (tight coupling)<\/li>\n<li>Traverse a deep structure like <code>data.value.collection.items<\/code> (brittle)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The entry composable provides a typed accessor that pulls a specific entry from an already-fetched collection, with proper null handling and type narrowing. If the data is already present in the SSR payload, it reuses it \u2014 no extra query.<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart LR\n  A[Page-level component] --&gt; B[\"usePageByPathQuery&lt;br\/&gt;(fetch collection)\"]\n  B --&gt; C[\"SSR payload&lt;br\/&gt;cached collection\"]\n\n  C --&gt; D[Child component]\n\n  subgraph \"Without entry composable\"\n    D --&gt; E1[Re-fetch collection]\n    D --&gt; E2[Accept entry via props]\n    D --&gt; E3[\"Traverse deep structure&lt;br\/&gt;data.value.collection.items\"]\n  end\n\n  C --&gt; F[\"usePageByPathEntry&lt;br\/&gt;(entry composable)\"]\n  F --&gt; G[\"Child component gets&lt;br\/&gt;typed single entry&lt;br\/&gt;no extra query\"]<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">I18NT \u2014 Typed Internationalization<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most Vue projects wire up <code>vue-i18n<\/code> with dotted key strings like <code>t('common.buttons.submit')<\/code>. It works, but has two serious drawbacks:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>No type safety.<\/strong> A typo in the key becomes a runtime error and leaks the raw key to the UI. Renaming a key requires global find-and-replace with no compiler support.<\/li>\n<li><strong>Poor discoverability.<\/strong> To find the right key, you have to open YAML files, scan nested structures, and mentally map them to code. There is no way to explore translations directly from the editor.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">I18NT fixes both by generating a TypeScript interface tree that mirrors the translation file structure, then wrapping <code>vue-i18n<\/code> in a <strong>JavaScript Proxy chain<\/strong> that turns translation keys into a navigable, type-safe object with full IDE autocomplete.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Generation Pipeline<\/h3>\n\n\n\n<pre class=\"mermaid\">flowchart LR\n  A[\"Translation source&lt;br\/&gt;i18n\/locales\/de\/common.yaml\"] --&gt; B[Build-time generator]\n\n  subgraph \"YAML structure\"\n    A1[buttons.submit: 'Absenden']\n    A2[buttons.cancel: 'Abbrechen']\n    A3[validation.required: 'Pflichtfeld']\n    A4[validation.email: 'Ung\u00fcltige E-Mail']\n    A5[\"currency.monthly: '{@:currency:{0}}\/Monat'\"]\n  end\n\n  A --&gt; A1\n  A --&gt; A2\n  A --&gt; A3\n  A --&gt; A4\n  A --&gt; A5\n\n  B --&gt; C[Generated .nuxt\/i18nt\/types.ts]\n\n  subgraph \"Generated TypeScript interface\"\n    C1[\"interface CommonTranslations {&lt;br\/&gt;buttons: { submit: string; cancel: string }&lt;br\/&gt;validation: { required: string; email: string }&lt;br\/&gt;currency: { monthly: (amount: number) =&gt; string }&lt;br\/&gt;}\"]\n  end\n\n  C --&gt; C1<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">The Proxy Chain<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">These generated types feed into a Proxy-based wrapper around <code>vue-i18n<\/code>:<\/p>\n\n\n\n<pre class=\"mermaid\">sequenceDiagram\n  participant Dev as Developer\n  participant T as t proxy root\n  participant P as Proxy handler\n  participant I18N as vue-i18n\n\n  Dev-&gt;&gt;T: t.common.buttons.submit\n  T-&gt;&gt;P: access 'common'\n  P-&gt;&gt;P: build key \"common\"\n  P-&gt;&gt;P: access 'buttons'\n  P-&gt;&gt;P: build key \"common.buttons\"\n  P-&gt;&gt;P: access 'submit'\n  P-&gt;&gt;P: build key \"common.buttons.submit\"\n  P-&gt;&gt;I18N: t(\"common.buttons.submit\")\n  I18N--&gt;&gt;Dev: \"Absenden\"\n\n  Note over Dev,P: IDE autocompletion &amp; TS types&lt;br\/&gt;for each property access<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At runtime, the Proxy chain is just a handful of property accesses. For the developer, it delivers two big wins: <strong>type safety<\/strong> that catches mistakes at compile time, and <strong>discoverability<\/strong> that lets you browse translations via <code>t.<\/code> and IntelliSense. A developer who has never opened the YAML files can still find the right key without leaving the component.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Format Annotations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Translation strings with parameters (such as <code>{@:currency:{0}}\/Monat<\/code>) are analyzed at build time. The generator encodes parameter types into the generated interface:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>{0}<\/code> \u2192 the function signature includes a positional <code>string<\/code> parameter<\/li>\n<li><code>{@:currency:{0}}<\/code> \u2192 recognized as a currency formatter, parameter typed as <code>number<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">As a result, <code>t.common.currency.monthly(29.99)<\/code> is type-checked: passing a string where a number is expected becomes a compile error.<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart TB\n  A[\"Translation string&lt;br\/&gt;{@:currency:{0}}\/Monat\"] --&gt; B[Build-time analyzer]\n\n  B --&gt; C[\"Detect placeholder {0}\"]\n  B --&gt; D[Detect currency formatter annotation]\n\n  C --&gt; E[Infer parameter position 0]\n  D --&gt; F[Infer parameter type number]\n\n  E &amp; F --&gt; G[\"Generate TypeScript&lt;br\/&gt;monthly(amount: number) =&gt; string\"]\n\n  G --&gt; H[\"Developer calls&lt;br\/&gt;t.common.currency.monthly(29.99)&lt;br\/&gt;\u2713 type-checked\"]\n  G --&gt; I[\"Developer calls&lt;br\/&gt;t.common.currency.monthly('29.99')&lt;br\/&gt;\u2717 compile error\"]<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Plop Scaffolding Generator<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In a large Nuxt-based codebase with dozens of internal modules, consistency is non-negotiable. Every module follows the same layout:<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart TB\n  subgraph \"modules\/my-module\/\"\n    A[\"index.ts&lt;br\/&gt;defineNuxtModule()\"]\n    subgraph runtime\n      B[\"composables\/&lt;br\/&gt;auto-imported composables\"]\n      C[\"components\/&lt;br\/&gt;auto-imported components\"]\n      D[\"server\/&lt;br\/&gt;Nitro handlers and plugins\"]\n      E[\"plugins\/&lt;br\/&gt;Nuxt plugins\"]\n    end\n    F[\"types.d.ts&lt;br\/&gt;module type declarations\"]\n    G[\"README.md&lt;br\/&gt;documentation\"]\n  end<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>plop<\/code> generator scaffolds this structure with a single command:<\/p>\n\n\n\n<pre><code class=\"language-bash\">$ yarn plop\n? Module name: my-feature\n? Include server handlers? Yes\n? Include DevTools tab? No\n\n\u2713 Created modules\/my-feature\/index.ts\n\u2713 Created modules\/my-feature\/runtime\/composables\/useMyFeature.ts\n\u2713 Created modules\/my-feature\/runtime\/server\/plugin.ts\n\u2713 Created modules\/my-feature\/README.md\n\u2713 Created modules\/my-feature\/types.d.ts<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The templates live as Handlebars files in <code>.plop-templates\/<\/code>, encoding the application\u2019s conventions. New developers do not need to memorize the module anatomy \u2014 the generator enforces it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Why Build-Time Generation Beats Runtime Magic<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A common alternative to code generation is runtime magic \u2014 Proxies, dynamic imports, and reflection that resolve behavior at execution time. Build-time generation has three clear advantages:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Aspect<\/th><th>Build-Time Generation<\/th><th>Runtime Magic<\/th><\/tr><\/thead><tbody><tr><td><strong>Type safety<\/strong><\/td><td>Full \u2014 IDE and compiler see everything<\/td><td>Partial \u2014 types often degrade to <code>any<\/code> or require manual casting<\/td><\/tr><tr><td><strong>Performance<\/strong><\/td><td>Zero runtime cost \u2014 emitted code is plain TypeScript<\/td><td>Runtime overhead from Proxies, reflection, dynamic resolution<\/td><\/tr><tr><td><strong>Debugging<\/strong><\/td><td>Generated files are readable and debuggable<\/td><td>Stack traces wind through Proxy traps and dynamic resolvers<\/td><\/tr><tr><td><strong>Tree-shaking<\/strong><\/td><td>Unused generated code is removed by the bundler<\/td><td>Runtime systems are opaque to tree-shakers<\/td><\/tr><tr><td><strong>Discoverability<\/strong><\/td><td>IDE autocompletion exposes all APIs<\/td><td>Developers must memorize naming conventions<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<pre class=\"mermaid\">flowchart LR\n  subgraph BuildTime[Build-Time Generation]\n    BT1[Code generators in Nuxt modules]\n    BT2[Readable generated TS files]\n    BT3[\"Types visible to IDE &amp; compiler\"]\n  end\n\n  subgraph Runtime[Runtime Magic]\n    RT1[\"Proxies &amp; reflection at runtime\"]\n    RT2[Dynamic imports \/ resolution]\n    RT3[Types often degraded to any]\n  end\n\n  BT1 --&gt; BT2 --&gt; BT3\n  RT1 --&gt; RT2 --&gt; RT3\n\n  BT3 --&gt; A[\"Strong type safety&lt;br\/&gt;and better DX\"]\n  RT3 --&gt; B[\"Weaker type safety&lt;br\/&gt;and harder debugging\"]\n\n  A --&gt; C[\"Preferred for Nuxt-integrated&lt;br\/&gt;enterprise codebases\"]\n  B --&gt; C<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">I18NT is intentionally hybrid: build-time generation for types (for full IDE support) plus a minimal runtime Proxy for ergonomics (<code>t.common.buttons.submit<\/code> instead of <code>t('common.buttons.submit')<\/code>). The Proxy is a thin wrapper around <code>vue-i18n<\/code>, with negligible overhead, but it turns translation files into a navigable API.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Combined Effect<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">GQLT and I18NT are not the only generators in play. In a typical enterprise Nuxt stack, additional modules often follow the same pattern:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Introspect Forms<\/strong> \u2014 uses generated GraphQL schema introspection types to automatically pick the right input component for each field (text inputs, selects, radios, date pickers) based on field type and enum values. Developers only supply overrides \u2014 layout, visibility conditions, custom components \u2014 not the field definitions themselves.<\/li>\n<li><strong>Validation Rules<\/strong> \u2014 generates client-side validation rules from a backend validation framework (for example, a .NET or Node validation library that defines rules on backend models). The generated rules guarantee that frontend and backend enforce the same constraints without duplication.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Together with the GraphQL code generator from the previous article, these modules form a generation pipeline where each layer builds on the previous one:<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart TB\n  subgraph \"Developer-written sources\"\n    A1[queries\/cms\/page.graphql]\n    A2[queries\/backend\/offers.graphql]\n    A3[i18n\/locales\/de\/common.yaml]\n    A4[i18n\/locales\/de\/forms.yaml]\n    A5[Backend GraphQL schema]\n  end\n\n  subgraph \"Generators\"\n    G1[GQLT module]\n    G2[I18NT module]\n    G3[Forms \/ validation generators]\n  end\n\n  A1 --&gt; G1\n  A2 --&gt; G1\n  A3 --&gt; G2\n  A4 --&gt; G2\n  A5 --&gt; G3\n\n  subgraph \"Generated artifacts (auto-imported)\"\n    B1[usePageQuery.ts]\n    B2[useOffersQuery.ts]\n    B3[typed t.common.*]\n    B4[typed t.forms.*]\n    B5[Form field definitions]\n    B6[Validation rules]\n    B7[TypeScript interfaces for API responses]\n    B8[useAsyncData wrappers]\n  end\n\n  G1 --&gt; B1\n  G1 --&gt; B2\n  G1 --&gt; B7\n  G1 --&gt; B8\n\n  G2 --&gt; B3\n  G2 --&gt; B4\n\n  G3 --&gt; B5\n  G3 --&gt; B6\n\n  subgraph \"What the developer never writes\"\n    N1[TS interfaces for API responses]\n    N2[Import statements for composables]\n    N3[Translation key strings]\n    N4[Manual useAsyncData wrappers]\n    N5[Form field configuration]\n    N6[Client-side validation logic]\n    N7[Error handling boilerplate]\n  end\n\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N1\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N2\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N3\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N4\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N5\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N6\n  B1 &amp; B2 &amp; B3 &amp; B4 &amp; B5 &amp; B6 &amp; B7 &amp; B8 --&gt; N7<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The code a developer writes is only a slice of what the system runs. The rest is generated, type-checked, and auto-imported.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lessons Learned<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Nuxt modules are the right abstraction for build-time generation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Nuxt modules run at build time, see the full Nuxt configuration, can declare auto-imports, and can watch files \u2014 they are a natural home for code generators. External tools like <code>graphql-codegen<\/code> handle schema-level generation; Nuxt modules handle framework-level integration.<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart LR\n  A[\"Nuxt module&lt;br\/&gt;(build-time)\"] --&gt; B[Access Nuxt config]\n  A --&gt; C[Declare auto-imports]\n  A --&gt; D[Watch project files]\n  A --&gt; E[Emit generated code into .nuxt\/]\n\n  subgraph \"External tools (e.g. graphql-codegen)\"\n    X1[Schema-level types]\n    X2[Operation-level TS types]\n  end\n\n  X1 --&gt; F[Feed into Nuxt modules]\n  X2 --&gt; F\n\n  F --&gt; E<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Generated code should be inspectable<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Every generated file in <code>.nuxt\/gqlt\/<\/code> and <code>.nuxt\/i18nt\/<\/code> is readable TypeScript. Developers can open them, understand them, and step through them in a debugger. That transparency builds trust and keeps debugging routine.<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart TB\n  A[Generator runs at build time] --&gt; B[\"Emit .nuxt\/gqlt\/*.ts&lt;br\/&gt;.nuxt\/i18nt\/*.ts\"]\n  B --&gt; C[Developer opens generated file]\n  C --&gt; D[Readable TS with clear structure]\n  D --&gt; E[Step through in debugger]\n  E --&gt; F[Trust in generation pipeline]<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">The Proxy pattern is underused in TypeScript projects<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">JavaScript Proxies are powerful but often avoided because they are hard to type. I18NT\u2019s approach \u2014 generating the type interfaces at build time and applying them to a Proxy at runtime \u2014 delivers Proxy ergonomics with static type safety. This pattern works well far beyond internationalization.<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart LR\n  A[\"Domain schema&lt;br\/&gt;(YAML, GraphQL, etc.)\"] --&gt; B[Build-time type generator]\n  B --&gt; C[Generated TS interfaces]\n\n  C --&gt; D[Typed Proxy wrapper]\n  D --&gt; E[\"Ergonomic API&lt;br\/&gt;(e.g. t.common.buttons.submit)\"]\n  C --&gt; F[Compiler-enforced types]\n\n  E &amp; F --&gt; G[\"Proxy ergonomics&lt;br\/&gt;+ static type safety\"]<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Scaffolding generators enforce consistency at scale<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At 35+ modules, consistency is a necessity. The plop generator makes sure every module follows the same patterns and ships with the same documentation structure. New developers (human or AI) can orient themselves in any module once they recognize the pattern.<\/p>\n\n\n\n<pre class=\"mermaid\">flowchart TB\n  A[Developer runs plop] --&gt; B[\"Answer prompts&lt;br\/&gt;(name, server handlers, DevTools tab)\"]\n  B --&gt; C[\"Apply Handlebars templates&lt;br\/&gt;from .plop-templates\/\"]\n  C --&gt; D[Create module folder structure]\n\n  D --&gt; E[Consistent layout across 35+ modules]\n  E --&gt; F[Faster onboarding]\n  E --&gt; G[\"Lower cognitive load&lt;br\/&gt;when navigating codebase\"]<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What&#8217;s Next<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Article 5<\/strong>: <em>Nuxt and Headless CMS \u2014 Why It&#8217;s Hard and How We Made It Work<\/em> \u2014 Content-driven routing, dynamic component rendering, and the preview system.  <\/li>\n<li><strong>Article 6<\/strong>: <em>Performance Optimization \u2014 Chasing That 100% Lighthouse Score<\/em> \u2014 Multi-tier caching, deferred hydration, and the performance techniques that add up.  <\/li>\n<li><strong>Article 7<\/strong>: <em>Type-Safe Form Generation from GraphQL Introspection<\/em> \u2014 How the backend schema drives form rendering, validation, and field configuration without any frontend duplication.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Munir Husseini is a software architect specializing in full-stack TypeScript, .NET, and cloud-native architectures.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Seventh in a series about migrating from legacy architectures to a modern Nuxt 4 stack. Beyond External Generators The previous article discussed GraphQL code generation using external tools like graphql-codegen. Those tools are excellent for generating types and composables from .graphql files, but in a large enterprise application they break down in two important areas: [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":222,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[5],"tags":[],"class_list":["post-14","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-advanced-web-app-with-nuxt-and-net"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules - Software Production<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/softwareproduction.eu\/?p=14\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules - Software Production\" \/>\n<meta property=\"og:description\" content=\"Seventh in a series about migrating from legacy architectures to a modern Nuxt 4 stack. Beyond External Generators The previous article discussed GraphQL code generation using external tools like graphql-codegen. Those tools are excellent for generating types and composables from .graphql files, but in a large enterprise application they break down in two important areas: [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/softwareproduction.eu\/?p=14\" \/>\n<meta property=\"og:site_name\" content=\"Software Production\" \/>\n<meta property=\"article:published_time\" content=\"2026-06-06T21:48:28+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-07T01:21:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1880\" \/>\n\t<meta property=\"og:image:height\" content=\"1055\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Munir Husseini\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Munir Husseini\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14\"},\"author\":{\"name\":\"Munir Husseini\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#\\\/schema\\\/person\\\/fec48f54713e1bd117640fb9b748802f\"},\"headline\":\"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules\",\"datePublished\":\"2026-06-06T21:48:28+00:00\",\"dateModified\":\"2026-06-07T01:21:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14\"},\"wordCount\":1172,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/softwareproduction.eu\\\/wordpress\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/07-gqlt-and-i18nt-modules.jpg\",\"articleSection\":[\"Advanced Web App with Nuxt and .NET\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14\",\"url\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14\",\"name\":\"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules - Software Production\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/softwareproduction.eu\\\/wordpress\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/07-gqlt-and-i18nt-modules.jpg\",\"datePublished\":\"2026-06-06T21:48:28+00:00\",\"dateModified\":\"2026-06-07T01:21:48+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/softwareproduction.eu\\\/?p=14\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#primaryimage\",\"url\":\"https:\\\/\\\/softwareproduction.eu\\\/wordpress\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/07-gqlt-and-i18nt-modules.jpg\",\"contentUrl\":\"https:\\\/\\\/softwareproduction.eu\\\/wordpress\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/07-gqlt-and-i18nt-modules.jpg\",\"width\":1880,\"height\":1055},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/?p=14#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/softwareproduction.eu\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#website\",\"url\":\"https:\\\/\\\/softwareproduction.eu\\\/\",\"name\":\"Softwareproduction\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/softwareproduction.eu\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#organization\",\"name\":\"Munir Husseini\",\"url\":\"https:\\\/\\\/softwareproduction.eu\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/softwareproduction.eu\\\/wordpress\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/softwareproduction-logo-32.png\",\"contentUrl\":\"https:\\\/\\\/softwareproduction.eu\\\/wordpress\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/softwareproduction-logo-32.png\",\"width\":32,\"height\":32,\"caption\":\"Munir Husseini\"},\"image\":{\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/softwareproduction.eu\\\/#\\\/schema\\\/person\\\/fec48f54713e1bd117640fb9b748802f\",\"name\":\"Munir Husseini\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b07845732d4d7bddfc43e608ae6662d564a14b35706dfae0c9610071d978f54e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b07845732d4d7bddfc43e608ae6662d564a14b35706dfae0c9610071d978f54e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b07845732d4d7bddfc43e608ae6662d564a14b35706dfae0c9610071d978f54e?s=96&d=mm&r=g\",\"caption\":\"Munir Husseini\"},\"sameAs\":[\"https:\\\/\\\/softwareproduction.eu\\\/\"],\"url\":\"https:\\\/\\\/softwareproduction.eu\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules - Software Production","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/softwareproduction.eu\/?p=14","og_locale":"en_US","og_type":"article","og_title":"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules - Software Production","og_description":"Seventh in a series about migrating from legacy architectures to a modern Nuxt 4 stack. Beyond External Generators The previous article discussed GraphQL code generation using external tools like graphql-codegen. Those tools are excellent for generating types and composables from .graphql files, but in a large enterprise application they break down in two important areas: [&hellip;]","og_url":"https:\/\/softwareproduction.eu\/?p=14","og_site_name":"Software Production","article_published_time":"2026-06-06T21:48:28+00:00","article_modified_time":"2026-06-07T01:21:48+00:00","og_image":[{"width":1880,"height":1055,"url":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg","type":"image\/jpeg"}],"author":"Munir Husseini","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Munir Husseini","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/softwareproduction.eu\/?p=14#article","isPartOf":{"@id":"https:\/\/softwareproduction.eu\/?p=14"},"author":{"name":"Munir Husseini","@id":"https:\/\/softwareproduction.eu\/#\/schema\/person\/fec48f54713e1bd117640fb9b748802f"},"headline":"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules","datePublished":"2026-06-06T21:48:28+00:00","dateModified":"2026-06-07T01:21:48+00:00","mainEntityOfPage":{"@id":"https:\/\/softwareproduction.eu\/?p=14"},"wordCount":1172,"commentCount":0,"publisher":{"@id":"https:\/\/softwareproduction.eu\/#organization"},"image":{"@id":"https:\/\/softwareproduction.eu\/?p=14#primaryimage"},"thumbnailUrl":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg","articleSection":["Advanced Web App with Nuxt and .NET"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/softwareproduction.eu\/?p=14#respond"]}]},{"@type":"WebPage","@id":"https:\/\/softwareproduction.eu\/?p=14","url":"https:\/\/softwareproduction.eu\/?p=14","name":"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules - Software Production","isPartOf":{"@id":"https:\/\/softwareproduction.eu\/#website"},"primaryImageOfPage":{"@id":"https:\/\/softwareproduction.eu\/?p=14#primaryimage"},"image":{"@id":"https:\/\/softwareproduction.eu\/?p=14#primaryimage"},"thumbnailUrl":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg","datePublished":"2026-06-06T21:48:28+00:00","dateModified":"2026-06-07T01:21:48+00:00","breadcrumb":{"@id":"https:\/\/softwareproduction.eu\/?p=14#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/softwareproduction.eu\/?p=14"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/softwareproduction.eu\/?p=14#primaryimage","url":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg","contentUrl":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg","width":1880,"height":1055},{"@type":"BreadcrumbList","@id":"https:\/\/softwareproduction.eu\/?p=14#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/softwareproduction.eu\/"},{"@type":"ListItem","position":2,"name":"Nuxt-Based Code Generation \u2014 The GQLT and I18NT Modules"}]},{"@type":"WebSite","@id":"https:\/\/softwareproduction.eu\/#website","url":"https:\/\/softwareproduction.eu\/","name":"Softwareproduction","description":"","publisher":{"@id":"https:\/\/softwareproduction.eu\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/softwareproduction.eu\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/softwareproduction.eu\/#organization","name":"Munir Husseini","url":"https:\/\/softwareproduction.eu\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/softwareproduction.eu\/#\/schema\/logo\/image\/","url":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/05\/softwareproduction-logo-32.png","contentUrl":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/05\/softwareproduction-logo-32.png","width":32,"height":32,"caption":"Munir Husseini"},"image":{"@id":"https:\/\/softwareproduction.eu\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/softwareproduction.eu\/#\/schema\/person\/fec48f54713e1bd117640fb9b748802f","name":"Munir Husseini","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/b07845732d4d7bddfc43e608ae6662d564a14b35706dfae0c9610071d978f54e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/b07845732d4d7bddfc43e608ae6662d564a14b35706dfae0c9610071d978f54e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b07845732d4d7bddfc43e608ae6662d564a14b35706dfae0c9610071d978f54e?s=96&d=mm&r=g","caption":"Munir Husseini"},"sameAs":["https:\/\/softwareproduction.eu\/"],"url":"https:\/\/softwareproduction.eu\/?author=1"}]}},"jetpack_featured_media_url":"https:\/\/softwareproduction.eu\/wordpress\/wp-content\/uploads\/2026\/06\/07-gqlt-and-i18nt-modules.jpg","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=14"}],"version-history":[{"count":10,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/posts\/14\/revisions"}],"predecessor-version":[{"id":223,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/posts\/14\/revisions\/223"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=\/wp\/v2\/media\/222"}],"wp:attachment":[{"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/softwareproduction.eu\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}