08 अग॰ 2025·6 मिनट पढ़ने में

सुरक्षित रीजनरेशन के साथ जनरेटेड UI में कस्टम Vue घटक

सीखें कि कैसे आप जनरेटेड UI में रीजनरेशन को प्रभावित किए बिना कस्टम Vue घटक जोड़ सकते हैं — आइसोलेशन पैटर्न, स्पष्ट सीमाएँ और सरल हैंडऑफ नियमों का उपयोग करके।

सुरक्षित रीजनरेशन के साथ जनरेटेड UI में कस्टम Vue घटक

What breaks when you edit a generated UI

Generated UIs are meant to be rebuilt. In platforms like AppMaster, Vue3 web app code is produced from visual builders. Regeneration is how changes stay consistent across screens, logic, and data models.

The catch is simple: if you edit generated files directly, the next regenerate can overwrite your edits.

That’s why teams reach for custom code. Built-in UI blocks often cover standard forms and tables, but real apps usually need a few special pieces: complex charts, map pickers, rich text editors, signature pads, or drag and drop planners. Those are good reasons to add custom Vue components, as long as you treat them like add-ons, not edits.

When custom code mixes with generated code, failures can be delayed and confusing. You might not notice until the next UI change forces a regenerate, or until a teammate adjusts a screen in the visual editor. Common problems include:

  • Your custom markup disappears because the template was regenerated.
  • Imports or registration break because file names or structure changed.
  • A “tiny fix” becomes a merge conflict on every deploy.
  • Generated logic and custom logic drift, so edge cases start failing.
  • Upgrades feel risky because you don’t know what will be replaced.

The goal isn’t to avoid customization. It’s to make rebuilds predictable. If you keep a clean boundary between generated screens and custom widgets, regeneration stays routine instead of stressful.

A boundary rule that keeps regeneration safe

If you want customization without losing work, follow one rule: never edit generated files. Treat them as read-only output, like a compiled artifact.

Think of your UI as two zones:

  • Generated zone: pages, layouts, and screens produced by the generator.
  • Custom zone: your hand-written Vue components in a separate folder.

The generated UI should consume your custom components. It shouldn’t be the place where those components are built.

To make that work long term, keep the “border” small and clear. A custom widget should behave like a small product with a contract:

  • Props in: only what it needs to render.
  • Events out: only what the page needs to react.

Avoid reaching into global state or calling unrelated APIs from inside the widget unless that’s explicitly part of the contract.

With AppMaster-style generated Vue3 screens, this typically means you do minimal wiring in the generated screen to pass props and handle events. That wiring may change across regenerations, but it stays small and easy to redo. The real work stays safe in the custom zone.

Isolation patterns that work well with Vue3

The goal is straightforward: regeneration should freely replace generated files, while your widget code stays untouched.

A practical approach is to keep bespoke widgets as a small internal module: components, styles, and helper utilities in one place. In generated Vue3 apps, that usually means custom code lives outside generated pages and is imported as a dependency.

A wrapper component helps a lot. Let the wrapper talk to the generated app: read the page’s existing data shape, normalize it, and pass clean props into the widget. If the generated data shape changes later, you often update the wrapper instead of rewriting the widget.

A few patterns hold up well:

  • Treat the widget as a black box: props in, events out.
  • Use a wrapper to map API responses, dates, and IDs into widget-friendly formats.
  • Keep styles scoped so regenerated pages don’t accidentally override your widget.
  • Don’t rely on parent DOM structure or page-specific class names.

On styling, prefer scoped CSS (or CSS Modules) and namespace shared classes. If the widget needs to match the app theme, pass theme tokens as props (colors, spacing, font size) instead of importing page styles.

Slots can be safe when they stay small and optional, like an “empty state” message. If slots start controlling core layout or behavior, you’ve moved the widget back into the generated layer, which is where regeneration pain starts.

Designing a stable component contract (props and events)

The safest way to keep regeneration painless is to treat each widget like a stable interface. Generated screens can change. Your component shouldn’t.

Start with inputs (props). Keep them few, predictable, and easy to validate. Prefer simple primitives and plain objects you control. Add defaults so the widget behaves well even when a screen passes nothing yet. If something can be malformed (IDs, date strings, enum-like values), validate it and fail softly: show an empty state instead of crashing.

For outputs, standardize events so widgets feel consistent to the rest of the app. A reliable set is:

  • update:modelValue for v-model
  • change for user-confirmed changes (not every keystroke)
  • error when the component can’t complete its job
  • ready when async work finishes and the widget is usable

If async work is involved, make it part of the contract. Expose loading and disabled props, and consider errorMessage for server-side failures. If the component fetches data on its own, still emit error and ready so the parent can react (toast, logging, fallback UI).

Accessibility expectations

Bake accessibility into the contract. Accept a label (or ariaLabel) prop, document keyboard behavior, and keep focus predictable after actions.

For example, a timeline widget on a dashboard should support arrow keys to move between items, Enter to open details, and it should return focus to the control that opened a dialog when the dialog closes. This makes the widget reusable across regenerated screens without extra rework.

Step by step: add a bespoke widget without touching generated files

Ship one bespoke widget
Add a timeline or chart widget to a real screen without risky manual edits.
डैशबोर्ड बनाएं

Start small: one screen users care about, one widget that makes it feel distinct. Keeping the first change narrow makes it easier to see what regeneration does and doesn’t affect.

  1. Create the component outside the generated area. Put it in a folder you own and keep in source control (often a custom or extensions directory).

  2. Keep the public surface small. A few props in, a few events out. Don’t pass the whole page state.

  3. Add a thin wrapper you also own. Its job is to translate “generated page data” into the widget contract.

  4. Integrate through a supported extension point. Reference the wrapper in a way that doesn’t require editing generated files.

  5. Regenerate and verify. Your custom folder, wrapper, and component should remain unchanged and still compile.

Keep boundaries sharp. The widget focuses on display and interaction. The wrapper maps data and forwards actions. Business rules stay in the app’s logic layer (backend or shared processes), not buried inside the widget.

A useful sanity check: if regeneration happens right now, could a teammate rebuild the app and get the same result without redoing manual edits? If yes, your pattern is solid.

Where to put logic so the UI stays maintainable

A custom widget should mostly worry about how it looks and how it responds to user input. The more business rules you pack into the widget, the harder it is to reuse, test, and change.

A good default is: keep business logic in the page or feature layer, and keep the widget “dumb.” The page decides what data the widget gets and what happens when the widget emits an event. The widget renders and reports user intent.

When you do need logic close to the widget (formatting, small state, client-side validation), hide it behind a small service layer. In Vue3, that can be a module, a composable, or a store with a clear API. The widget imports that API, not random app internals.

A practical split:

  • Widget (component): UI state, input handling, visuals, emits events like select, change, retry.
  • Service/composable: data shaping, caching, mapping API errors to user messages.
  • Page/container: business rules, permissions, which data to load, when to save.
  • Generated app parts: left untouched; pass data in and listen to events.

Avoid direct API calls inside the widget unless that’s explicitly the widget’s contract. If it owns fetching, make it obvious (name it like CustomerSearchWidget and keep call code in one service). Otherwise, pass items, loading, and error down as props.

Error messages should be user-facing and consistent. Instead of showing raw server text, map errors to a small set of messages your app uses everywhere, like “Couldn’t load data. Try again.” Include a retry action when possible, and log detailed errors outside the widget.

Example: a custom ApprovalBadge widget shouldn’t decide whether an invoice is approvable. Let the page compute status and canApprove. The badge emits approve, and the page runs the real rule and calls the backend (for example, the API you model in AppMaster), then passes clean success or error state back into the UI.

Common mistakes that cause pain after the next regenerate

Use the wrapper pattern
Translate generated page data into clean props so changes stay local.
रैपर जोड़ें

Most issues aren’t about Vue. They come from mixing custom work into places the generator owns, or relying on details that are likely to change.

The mistakes that most often turn a small widget into recurring cleanup:

  • Editing generated Vue files directly and forgetting what changed.
  • Using global CSS or broad selectors that quietly affect other screens when markup shifts.
  • Reading or mutating generated state shapes directly, so a harmless rename breaks the widget.
  • Packing too many page-specific assumptions into one component.
  • Changing the component API (props/events) without a migration plan.

A common scenario: you add a custom table widget and it works. A month later, a generated layout change means your global .btn rule now affects login and admin pages. Or a data object changes from user.name to user.profile.name, and the widget fails silently. The widget wasn’t the problem. The dependency on unstable details was.

Two habits prevent most of this:

First, treat generated code as read-only and keep custom files separate, with a clear import boundary.

Second, keep the component contract small and explicit. If you need to evolve it, add a simple version prop (for example apiVersion) or support both old and new prop shapes for one release.

Quick checklist before you ship a custom component

Use built-ins first
Lean on built-in auth and payments modules, then customize UI where it matters.
मॉड्यूल्स का उपयोग करें

Before you merge a bespoke widget into a generated Vue3 app, do a quick reality check. It should survive the next regenerate without heroics, and someone else should be able to reuse it.

  • Regenerate test: run a full regenerate and rebuild. If you had to re-edit a generated file, the boundary is wrong.
  • Clear inputs and outputs: props in, emits out. Avoid magic dependencies like grabbing external DOM or assuming a specific page store.
  • Style containment: scope styles and use a clear class prefix (for example, timeline-).
  • All states look OK: loading, error, and empty states should be present and sensible.
  • Reuse without cloning: confirm you can drop it on a second page by changing props and event handlers, not by copying internals.

A quick way to validate this: imagine adding the widget to an admin screen and then to a customer portal page. If both work with only prop changes and event handling, you’re in a safe place.

A realistic example: adding a timeline widget to a dashboard

A support team often wants one screen that tells the story of a ticket: status changes, internal notes, customer replies, and payment or delivery events. A timeline widget fits well, but you don’t want to edit generated files and lose work after the next regenerate.

The safe approach is to keep the widget isolated outside the generated UI and drop it into the page through a thin wrapper.

The widget contract

Keep it simple and predictable. For example, the wrapper passes:

  • ticketId (string)
  • range (last 7 days, last 30 days, custom)
  • mode (compact vs detailed)

The widget emits:

  • select when the user clicks an event
  • changeFilters when the user adjusts range or mode

Now the widget doesn’t know anything about the dashboard page, data models, or how requests are made. It renders a timeline and reports user actions.

How the wrapper connects it to the page

The wrapper sits next to the dashboard and translates page data into the contract. It reads the current ticket ID from page state, converts UI filters into a range, and maps backend records into the event format the widget expects.

When the widget emits select, the wrapper can open a details panel or trigger a page action. When it emits changeFilters, the wrapper updates page filters and refreshes data.

When the dashboard UI is regenerated, the widget stays untouched because it lives outside generated files. Usually, you only revisit the wrapper if the page renamed a field or changed how it stores filters.

Testing and release habits that prevent surprises

Keep logic out of widgets
Start with Data Designer and keep UI custom code focused on interaction only.
डेटा मॉडल करें

Custom components usually fail in boring ways: a prop shape changes, an event stops firing, or a generated page re-renders more often than your widget expects. A few habits catch these issues early.

Local testing: spot boundary breaks early

Treat the boundary between generated UI and your widget like an API. Test the widget without the full app first, using hardcoded props that match the contract.

Render it with “happy path” props and with missing values. Simulate key events (save, cancel, select) and confirm the parent handles them. Test slow data and small screens. Verify it doesn’t write to global state unless that’s part of the contract.

If you’re building on an AppMaster Vue3 web app, run these checks before you regenerate anything. It’s easier to diagnose a boundary issue when you haven’t changed two things at once.

Regression after regeneration: what to re-check first

After each regeneration, re-check the touchpoints: are the same props passed, and are the same events handled? That’s where breakage usually shows up first.

Keep inclusion predictable. Avoid fragile imports that depend on file paths that might move. Use one stable entry point for your custom components.

For production, add lightweight logging and error capture inside the widget:

  • Mounted with key props (sanitized)
  • Contract violations (missing required prop, wrong type)
  • Failed API calls with a short error code
  • Unexpected empty states

When something breaks, you want to quickly answer: did regeneration change the inputs, or did the widget change?

Next steps: make the pattern repeatable across your app

Once the first widget works, the real win is making it repeatable so the next one isn’t a one-off hack.

Create a small internal standard for widget contracts and write it down where your team keeps app notes. Keep it simple: naming, required vs optional props, a small event set, error behavior, and clear ownership (what lives in generated UI vs your custom folder).

Also write the boundary rules in plain language: don’t edit generated files, keep custom code isolated, and pass data only through props and events. It prevents the “quick fix” that turns into a permanent maintenance tax.

Before building a second widget, run a small regeneration trial. Ship the first widget, then regenerate at least twice during normal changes (a label change, a layout change, a new field) and confirm nothing breaks.

If you’re using AppMaster, it often works best to keep most UI and logic in the visual editors (UI builders, Business Process Editor, and Data Designer). Save custom Vue components for truly bespoke widgets the editors can’t express, like specialized timelines, chart interactions, or unusual input controls. If you want a clean starting point for this approach, AppMaster on appmaster.io is designed around regeneration, so keeping custom widgets isolated becomes a natural part of the workflow.

सामान्य प्रश्न

Why do my UI changes disappear after I regenerate the app?

जनरेट किए गए Vue फाइलों को एडिट करना जोखिम भरा है क्योंकि रीजनरेशन उन्हें पूरी तरह ओवरराइट कर सकता है। भले ही आपकी बदलवा एक बार बच जाए, बिल्डर में एक छोटा बदलाव टेम्पलेट को फिर से बना सकता है और आपकी मैन्युअल ट्वीक मिटा सकता है।

How can I customize a generated UI without losing work on the next regenerate?

सारी हैंड-रिटन Vue कोड एक अलग, आपके मालिकाने वाले फोल्डर (उदाहरण: custom या extensions) में रखें और उसे dependency के रूप में इम्पोर्ट करें। जनरेटेड पेजों को रीड-ओनली मानें और सिर्फ एक छोटा, स्थिर इंटरफ़ेस के जरिए अपने कम्पोनेंट्स से कनेक्ट करें।

What is a wrapper component and why does it help with generated screens?

रैपर एक पतला कम्पोनेंट होता है जो आप अपने पास रखते हैं और जनरेटेड पेज और आपके विजेट के बीच बैठता है। यह पेज के डेटा शेप को साफ props में बदलता है और विजेट के इवेंट्स को पेज एक्शन्स में तब्दील करता है—इसलिए अगर बाद में जनरेटेड डेटा बदले तो अक्सर आपको केवल रैपर अपडेट करना होता है।

What’s the safest way to design props and events for a reusable widget?

कॉन्ट्रैक्ट छोटा रखें: विजेट को जितना डेटा चाहिए उतने ही props दें, और कुछ ही इवेंट्स से यूजर इरादा रिपोर्ट कराएं। सरल वैल्यूज़ और आपके नियंत्रित ऑब्जेक्ट्स पसंद करें, डिफ़ॉल्ट जोड़ें, इनपुट वेलिडेट करें और क्रैश करने की बजाय सॉफ्ट फेल करें (खाली स्टेट दिखाएँ)।

When should I emit `update:modelValue` vs `change` from a custom component?

update:modelValue तब उपयोगी है जब विजेट एक फॉर्म कंट्रोल की तरह व्यवहार करे और v-model सपोर्ट करे। change ऐसे मामलों के लिए बेहतर है जब यूज़र ने पुष्टि की हुई क्रिया की हो (जैसे Save), ताकि पैरेंट हर कीस्ट्रोक को प्रोसेस न करे।

How do I prevent my widget’s CSS from breaking other generated pages?

अपने विजेट की स्टाइल्स को स्कोप करें और स्पष्ट क्लास प्रीफिक्स उपयोग करें ताकि जनरेटेड पेज्स आपके CSS को अनजाने में ओवरराइड न कर दें। अगर विजेट को ऐप थीम से मिलाना है तो पेज-लेवल स्टाइल इम्पोर्ट करने की बजाय रंग, स्पेसिंग और फॉन्ट-आकार जैसे थीम टोकन props के रूप में पास करें।

Where should business logic live if I add custom UI components?

डिफ़ॉल्ट रूप से बिजनेस नियम विजेट के बाहर रखें। पेज या बैकएंड तय करें कि कौन से डेटा और परमीशन्स सही हैं; विजेट केवल रेंडर और इंटरैक्शन का काम करे और select, retry, approve जैसे इवेंट्स के माध्यम से इरादा रिपोर्ट करे।

What are the most common reasons custom components break after regeneration?

अस्थिर विवरणों पर निर्भरता से बचें—जैसे जनरेटेड फाइल पाथ, पेरेंट DOM स्ट्रक्चर, या आंतरिक स्टेट ऑब्जेक्ट शेप। अगर इन्हें चाहिए तो उनको एक रैपर में छिपाएँ ताकि कोई फील्ड रीनेम (user.nameuser.profile.name) विजेट को पूरी तरह तोड़ न दे।

What should I test before and after I regenerate to catch issues early?

विजेट को अलग करके और हार्डकोडेड props के साथ अलग से टेस्ट करें—खुशनुमा पाथ और मिissिंग/गलत वैल्यू के साथ। फिर रीजनरेट करें और सबसे पहले यह देखें: क्या वही props पास हो रहे हैं, और क्या वही इवेंट्स हैंडल हो रहे हैं।

When is it worth building a bespoke Vue widget instead of using built-in UI blocks?

हर UI को कस्टम कोड की ज़रूरत नहीं होती। विजुअल बिल्डर्स से एक्सप्रेस न होने वाले स्पेशल केस—जैसे जटिल चार्ट, मैप पिकर, सिग्नेचर पैड, या ड्रैग-एंड-ड्रॉप प्लानर्स—के लिए ही कस्टम कम्पोनेंट बनाना ज़्यादा उपयोगी होता है। अगर विजुअल एडिटर्स से काम चल सकता है तो वह लंबी अवधि में संभालना आसान होगा।

शुरू करना आसान
कुछ बनाएं अद्भुत

फ्री प्लान के साथ ऐपमास्टर के साथ प्रयोग करें।
जब आप तैयार होंगे तब आप उचित सदस्यता चुन सकते हैं।

शुरू हो जाओ