GrapesJS + TypeScript

GrapesJS TypeScript: पूर्ण एकीकरण गाइड

TypeScript के साथ GrapesJS का उपयोग करना सीखें, टाइप किए गए संपादक एपीआई और ईवेंट के साथ काम करें, कस्टम घटक और प्लगइन्स बनाएं, स्टोरेज कनेक्ट करें और GrapesJS को React, Next.js, Vue या Angular एप्लिकेशन में एकीकृत करें।

पैकेज में प्रकारटाइप किए गए संपादक एपीआईकस्टम घटकप्लगइन विकासHTML/CSS निर्यातReact · Vue · Angular · Next.js
संक्षिप्त उत्तर

क्या GrapesJS TypeScript का समर्थन करता है?

हाँ - और प्रकार पैकेज के अंदर जहाज करते हैं।

GrapesJS 0.23.6 Dist/index.d.ts पर अपनी स्वयं की घोषणा फ़ाइल प्रकाशित करता है, जिसे पैकेज के अपने प्रकार फ़ील्ड से संदर्भित किया गया है। grapesjs स्थापित करने से आपको संपादक और उसके प्रकार एक निर्भरता में मिलते हैं, इसलिए 'Editor' से grapesjs आयात करना बिना किसी अतिरिक्त सेटअप और बिना किसी दूसरे पैकेज के हल हो जाता है।

  • @types/grapesjs स्थापित न करें। वह पैकेज npm पर बिल्कुल भी प्रकाशित नहीं होता है - आपको चुपचाप बासी प्रकार देने के बजाय E404 के साथ इंस्टॉल विफल हो जाता है।
  • कोई GrapesJS v1.x नहीं है। वर्तमान रिलीज़ 0.23.6, लाइसेंस प्राप्त BSD-3-Clause है। 1.x लाइन के बारे में बात करने वाले ट्यूटोरियल एक ऐसे संस्करण का वर्णन कर रहे हैं जो मौजूद नहीं है।
  • TypeScript 5.0 मंजिल है। घोषणा फ़ाइल एक स्थिरांक प्रकार पैरामीटर का उपयोग करती है, इसलिए 4.9 और नीचे इसे पार्स नहीं कर सकता है - और विफलता को "मॉड्यूल 'grapesjs' नहीं मिल सकता" के रूप में रिपोर्ट करता है, जो अधिकांश लोगों को एक प्रकार के पैकेज की तलाश में भेजता है जिसकी उन्हें आवश्यकता नहीं है।

प्रकार क्या कवर करते हैं संपादक की API सतह - संपादक उदाहरण, इसके प्रबंधक, घटक, ब्लॉक, ईवेंट और प्रोजेक्ट डेटा। वे आपके उत्पाद के अपने मॉडल का वर्णन नहीं करते हैं, और यह मार्गदर्शिका काफी हद तक उन दो चीजों को अलग रखने के बारे में है।

इसे स्थापित करें और शुरू करें
मार्ग

आप क्या सीखेंगे

बारह चरण, क्रम में। प्रत्येक उस अनुभाग से लिंक करता है जो इसे कवर करता है, ताकि आप शुरू कर सकें कि आपका प्रोजेक्ट वास्तव में कहां है।

  1. GrapesJS को TypeScript के साथ स्थापित करेंएक निर्भरता, कोई प्रकार पैकेज नहीं, और रनटाइम आयात और केवल प्रकार के आयात के बीच का अंतर।
  2. कॉन्फ़िगर करें TypeScriptचार कंपाइलर विकल्प जो संपादक के काम के लिए मायने रखते हैं - और क्यों strictNullChecks वास्तविक काम कर रहा है।
  3. संपादक टाइप करेंgrapesjs.init Editor लौटाता है। इसे Editor | null के रूप में धारण करना ही सबसे आम दुर्घटना को रोकता है।
  4. घटकों के साथ काम करेंComponent, ComponentDefinition, और addType हस्ताक्षर जो अधिकांश ट्यूटोरियल गलत हो जाते हैं।
  5. प्रकार ब्लॉकBlockProperties संपादक से दूर घोषित किया गया है, इसलिए एक ब्लॉक की जांच अपने आप की जाती है।
  6. घटनाओं को संभालेंEditor.on ईवेंट के नाम से अपने कॉलबैक का अनुमान लगाता है - और आपके अपने ईवेंट के लिए खुला रहता है।
  7. प्लगइन्स बनाएंPlugin<Options> दोनों मापदंडों को टाइप करता है, और विकल्प इंटरफ़ेस का निर्यात करना ही इसे प्रयोग करने योग्य बनाता है।
  8. कस्टम घटक बनाएंएक रचित Hero, जिसे एक बार इंटरफ़ेस के रूप में वर्णित किया गया था और संपादक, API और रेंडरर द्वारा पुनः उपयोग किया गया था।
  9. भंडारण और API डेटा टाइप करेंProjectData संपादक का JSON है। ProjectRecord आपकी पंक्ति है। वे एक ही प्रकार के नहीं हैं।
  10. React के साथ GrapesJS का प्रयोग करेंआधिकारिक आवरण, और मैनुअल useEffect संस्करण - सफाई के साथ StrictMode की आवश्यकता होती है।
  11. Next.js के साथ GrapesJS का प्रयोग करेंक्लाइंट सीमा कहाँ जाती है, और इसके ऊपर संपादक क्यों नहीं बनाया जा सकता है।
  12. एक उत्पादन संपादक की संरचना करेंआपके एप्लिकेशन और संपादक के बीच एक सीम, इसलिए न तो दूसरे में लीक होता है।
चरण 1

1. GrapesJS TypeScript के साथ स्थापित करें

एक पैकेज है। प्रकार इसके साथ आते हैं, इसलिए आपके devDependencies में कोई दूसरा इंस्टॉल और कोई @types प्रविष्टि नहीं है।

पदासीन करनाbash
npm install grapesjs

न चलाने का आदेश

@types/grapesjs बहिष्कृत, अधिक्रमित या वैकल्पिक नहीं है - यह npm रजिस्ट्री से अनुपस्थित है। इसे चलाने से 404 मिलता है, और यदि आप इसे एक पुराने ट्यूटोरियल में देखते हैं जो एक विश्वसनीय संकेत है तो उस ट्यूटोरियल के बाकी हिस्से बंडल प्रकारों से भी पहले का है।

bash
# Don't. This package is not published — npm returns E404.
npm install --save-dev @types/grapesjs

रनटाइम आयात बनाम केवल-प्रकार आयात

grapesjs अपने आप में एक मान है: आप grapesjs.init() कहते हैं। Editor, Component और Block प्रकार हैं: वे केवल संकलन के दौरान मौजूद होते हैं। उन्हें import type के साथ चिह्नित करना इसे स्पष्ट करता है, और गारंटी देता है कि आयात आपके बंडल में खींचे जाने के बजाय मिटा दिया गया है - जो फ्रेमवर्क कोड में सबसे ज्यादा मायने रखता है, जहां संपादक का एक आवारा रनटाइम आयात इसे सर्वर रेंडर में खींच सकता है।

ts
// Runtime import: the value you actually call.
import grapesjs from 'grapesjs';

// Type-only import: erased at compile time, ships nothing to the bundle.
import type { Editor, Component, Block } from 'grapesjs';

// Editor styles. Without them the canvas renders unstyled.
import 'grapesjs/dist/css/grapes.min.css';
अगला: कंपाइलर को कॉन्फ़िगर करें
चरण 2

2. कॉन्फ़िगर करें TypeScript

आपको GrapesJS के लिए एक विशेष कॉन्फ़िगरेशन की आवश्यकता नहीं है। आपको चार विकल्पों को सही ढंग से सेट करने की आवश्यकता है - आपका बाकी tsconfig जो कुछ भी आपका प्रोजेक्ट पहले से उपयोग करता है वह रह सकता है।

tsconfig.jsonjson
{
  "compilerOptions": {
    // GrapesJS's bundled .d.ts uses const type parameters, a TypeScript 5.0
    // feature. On 4.9 and below the file fails to *parse*, and every import
    // from 'grapesjs' reports "Cannot find module".
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",

    // The editor manipulates real DOM nodes: container elements, iframes,
    // drag events. Without the DOM lib none of that type-checks.
    "lib": ["ES2020", "DOM", "DOM.Iterable"],

    // strict is what makes the typings worth having. In particular
    // strictNullChecks is what forces you to handle "editor not created yet",
    // which is the single most common GrapesJS runtime crash.
    "strict": true,

    "skipLibCheck": true,
    "esModuleInterop": true
  }
}
लक्ष्य और मॉड्यूल
ES2020 से ऊपर कुछ भी। घोषणा फ़ाइल टेम्पलेट शाब्दिक प्रकार और स्थिरांक प्रकार मापदंडों का उपयोग करती है, इसलिए बाधा TypeScript संस्करण है, उत्सर्जन लक्ष्य नहीं।
lib में DOM शामिल होना चाहिए
संपादक वास्तविक तत्वों, iframes और ड्रैग ईवेंट पर काम करता है। DOM lib के बिना, grapesjs.init({ container: element }) टाइप-चेक नहीं करता है और विफलता कॉन्फ़िगरेशन के बजाय GrapesJS समस्या की तरह दिखती है।
सख्त - विशेष रूप से strictNullChecks
यह वह विकल्प है जो इसे बनाए रखता है। यह आपको उस विंडो को संभालने के लिए मजबूर करता है जहां संपादक अभी तक मौजूद नहीं है: init से पहले, नष्ट करने के बाद, और रेफरी के पहले रेंडर पर। यह अंतर फ्रेमवर्क एकीकरण में रनटाइम त्रुटियों का सबसे आम स्रोत है।
moduleResolution
bundler Vite, Next.js और सबसे आधुनिक सेटअप के लिए; node16 या nodenext यदि आप Node के अपने एल्गोरिदम के माध्यम से हल कर रहे हैं। दोनों पैकेज के प्रकार फ़ील्ड का पता लगाते हैं।
चरण 3

3. GrapesJS प्रकारों को समझना

ये वे नाम हैं जिन्हें आप वास्तव में आयात करेंगे। प्रत्येक को दस्तावेज़ीकरण साइट से कॉपी करने के बजाय grapesjs 0.23.6 की घोषणा फ़ाइल के खिलाफ जाँच की गई थी, जो जावास्क्रिप्ट API का वर्णन करती है और हमेशा समान नामों का उपयोग नहीं करती है।

प्रकारप्रतिनिधित्व करता हैसामान्य उपयोग
Editorकक्षासंपादक उदाहरणसब कुछ: जीवनचक्र, प्रबंधक, निर्यात, घटनाएँ
EditorConfigइंटरफेसऑब्जेक्ट को इनिट में पास किया गयाकॉल साइट से दूर एक कॉन्फ़िगरेशन बनाना
Componentकक्षाकैनवास के पेड़ में एक नोडकिसी चयनित तत्व को पढ़ना और अद्यतन करना
ComponentDefinitionइंटरफेसएक घोषित घटक, एक उदाहरण नहींएक घटक के बच्चे; एक ब्लॉक की सामग्री
ComponentPropertiesइंटरफेसएक घटक के मॉडल फ़ील्डआपके द्वारा addType को पास किए गए डिफ़ॉल्ट टाइप करना
AddComponentTypeOptionsइंटरफेसतर्क addType वास्तव में लेता हैएक कस्टम घटक प्रकार पंजीकृत करना
Blockकक्षाBlock Manager में एक ब्लॉकBlocks.add का रिटर्न मूल्य
BlockPropertiesइंटरफेसएक ब्लॉक की घोषणाअपने स्वयं के मॉड्यूल में ब्लॉक घोषित करना
Traitकक्षासेटिंग पैनल में एक फ़ील्डकस्टम विशेषता प्रकार और विशेषता हैंडलर
ProjectDataइंटरफेससंपादक ने JSON सहेजाभंडारण भार और भंडारण; आपका डेटाबेस कॉलम
Plugin<T>इंटरफेसटाइप किए गए विकल्पों के साथ एक प्लगइन फ़ंक्शनआपके द्वारा लिखे गए या उपभोग किए जाने वाले प्लगइन को टाइप करना
PluginOptionsउपनाम टाइप करेंप्लगइन के विकल्पों पर बाधाजेनेरिक प्लगइन हेल्पर और रैपर

ये सभी नाम से आयात योग्य हैं: import type { Editor, Component, BlockProperties } 'grapesjs' से। केवल grapesjs को रनटाइम आयात की आवश्यकता होती है।

तीन नाम जिन्हें आप आयात नहीं कर सकते

प्रबंधक वर्गों को फ़ाइल में घोषित किया जाता है, लेकिन कभी निर्यात नहीं किया जाता है, इसलिए उन्हें नाम से आयात करना TS2614 के साथ विफल रहता है - एक भ्रमित करने वाली त्रुटि, क्योंकि जब आप इसकी तलाश में जाते हैं तो वर्ग स्पष्ट रूप से मौजूद होता है। इसके बजाय Editor में अनुक्रमणिका करें: गेटर का रिटर्न प्रकार एक ही वर्ग है, और उपनाम सभी संस्करणों में स्थिर है।

BlockManager
इसके बजाय उपयोग करेंEditor['Blocks']
StorageManager
इसके बजाय उपयोग करेंEditor['Storage']
ComponentManager
इसके बजाय उपयोग करेंEditor['Components']
चरण 4

4. GrapesJS Editor टाइप करें

grapesjs.init() एक Editor लौटाता है। चर को एनोटेट करना वैकल्पिक है - अनुमान पहले से ही इसे सही हो जाता है - लेकिन प्रकार का नामकरण वह है जो आपको संपादक को मॉड्यूल सीमाओं के पार बिना किसी भी चौड़ा किए बिना पास करने देता है।

एसआरसी/संपादक/createEditor.tsts
import grapesjs from 'grapesjs';
import type { Editor } from 'grapesjs';
import 'grapesjs/dist/css/grapes.min.css';

const editor: Editor = grapesjs.init({
  container: '#gjs',
  height: '100vh',
  storageManager: false,
});

// Both return values are typed, and they are not the same shape:
// getHtml() always returns a string, getCss() can return undefined.
const html: string = editor.getHtml();
const css: string | undefined = editor.getCss();
  • स्वतः पूर्ण उदाहरण का अनुसरण करता है: संपादक। प्रत्येक प्रबंधक को सूचीबद्ध करता है, और प्रत्येक प्रबंधक अपने वास्तविक हस्ताक्षर के साथ अपने स्वयं के तरीकों को सूचीबद्ध करता है।
  • getHtml() स्ट्रिंग लौटाता है; getCss() स्ट्रिंग लौटाता है | अपरिभाषित। अंतर वास्तविक है, और सख्त मोड आपको इसे संभालने के लिए प्रेरित करता है।
  • destroy() API का हिस्सा है, अतिरिक्त नहीं। फ्रेमवर्क की सफाई इस पर निर्भर करती है।

अशक्त संदर्भ, जहां मान है

एक ढांचे में संपादक पहले रेंडर के लिए मौजूद नहीं है, और अनमाउंट के बाद मौजूद नहीं होना चाहिए। धारक को Editor | null के रूप में टाइप करने से कंपाइलर प्रत्येक कॉल साइट पर दोनों क्षणों के बारे में पूछता है। इसे Editor के रूप में टाइप करना और इसे दूर करने से उस प्रश्न को उत्पादन में ले जाया जाता है।

ts
import type { Editor } from 'grapesjs';

// Not `let editor: Editor` — before init there is no editor, and the type
// should say so. Every call site is then forced to handle the empty case.
let editor: Editor | null = null;

export function exportHtml(): string {
  if (!editor) throw new Error('Editor is not initialised yet');
  return editor.getHtml(); // narrowed to Editor here
}

export function destroy(): void {
  editor?.destroy();
  editor = null;
}

प्रबंधकों तक पहुंचना

प्रत्येक प्रबंधक संपादक को लटका देता है - editor.Blocks, editor.Components, editor.Storage, editor.Commands - और प्रत्येक गेटर टाइप किया जाता है, इसलिए स्वतः पूर्ण उदाहरण से नीचे काम करता है। आप जो नहीं कर सकते वह नाम से प्रबंधक कक्षाओं को आयात करना है; इसके बजाय उन्हें Editor के माध्यम से उपनाम करें।

ts
import type { Editor } from 'grapesjs';

// These names are NOT exported from 'grapesjs' — importing them by name is a
// compile error. Index into Editor instead and you get the same classes.
type BlockManager = Editor['Blocks'];
type StorageManager = Editor['Storage'];
type ComponentManager = Editor['Components'];

export function countBlocks(blocks: BlockManager): number {
  return blocks.getAll().length;
}
अगला: संपादक जो करता है उस पर प्रतिक्रिया दें
चरण 5

5. GrapesJS में TypeScript घटनाओं के साथ कार्य करना

editor.on ईवेंट के नाम पर सामान्य है, इसलिए कॉलबैक हस्ताक्षर आपके द्वारा पास की गई स्ट्रिंग से लिया गया है। व्यवहार में इसका मतलब है कि आपको लगभग कुछ भी एनोटेट नहीं करना चाहिए - अनुमान आपको सही पैरामीटर प्रकार देता है, और एक एनोटेशन जो असहमत है वह एक मूक बेमेल के बजाय एक संकलन त्रुटि है।

एसआरसी/संपादक/events.tsts
import type { Editor } from 'grapesjs';

export function wireEditorEvents(editor: Editor): void {
  // No annotation needed. `component` is inferred as Component and
  // `options` carries `action`, which tells add from move from clone.
  editor.on('component:add', (component, options) => {
    console.log(component.get('type'), options.action);
  });

  // A different event, a different payload — the callback signature changes
  // with the event name, so a wrong parameter list is a compile error.
  editor.on('component:selected', (component) => {
    console.log(component.getId());
  });

  editor.on('storage:end:store', () => {
    console.log('Project saved');
  });
}

आपके द्वारा उपयोग किए जाने वाले ईवेंट परिवार

Component कार्यक्रम
component:add, component:remove, component:update, component:selected, component:mount. पहला तर्क Component है; component:add को एक विकल्प ऑब्जेक्ट भी मिलता है जिसकी क्रिया क्लोन से एक चाल से एक ऐड को अलग करती है।
Editor जीवनचक्र
एक बार संपादक तैयार होने के बाद, प्रोजेक्ट में किसी भी बदलाव पर अपडेट करें, टियरडाउन पर नष्ट करें। ये वे जगह हैं जहां आप अपने स्वयं के सेव इंडिकेटर या डर्टी-स्टेट फ्लैग को हुक करते हैं।
भंडारण कार्यक्रम
storage:start:store, storage:end:store, storage:error. सटीक रूप से उपयोगी है क्योंकि वे आपके स्वयं के भंडारण कार्यान्वयन के आसपास आग लगाते हैं, इसलिए एक असफल बचत कंसोल के बजाय UI में सतह पर आ सकती है।
Block कार्यक्रम
block:drag:start, block:drag:stop और Block Manager का अपना जोड़ें और निकालें। एनालिटिक्स के लिए आसान है जिस पर लोग वास्तव में पहुंचते हैं।

जहां अनुमान रुकता है

ईवेंट का नाम एक ओपन स्ट्रिंग यूनियन है, जानबूझकर: प्लगइन्स अपने स्वयं के चैनलों को परिभाषित करते हैं और उन्हें संकलित करते रहना चाहिए। लागत यह है कि एक मुख्य ईवेंट नाम में एक टाइपो अभी भी मान्य है TypeScript - कॉलबैक बस एक ढीले हस्ताक्षर पर वापस आ जाता है और कभी भी आग नहीं लगता। जब कोई ईवेंट हैंडलर रहस्यमय तरीके से कुछ नहीं करता है, तो API की जांच करने से पहले वर्तनी की जांच करें।

ts
import type { Editor } from 'grapesjs';

export function wireCustomEvents(editor: Editor): void {
  // Your own events are allowed — the event name is a string union that stays
  // open, so plugins can define their own channels.
  editor.on('my-plugin:published', (...args: unknown[]) => {
    console.log(args);
  });

  // Which is also the trade-off: this typo compiles. The callback simply falls
  // back to (...args: any[]) and never fires.
  // editor.on('component:selcted', (component) => { ... });
}
अगले: उन घटनाओं में वे घटक होते हैं
चरण 6

6. टाइप-सेफ GrapesJS Components

एक घटक प्रकार कैनवास में नए व्यवहार को पंजीकृत करता है: एक टैग, इसका traits, यह बच्चों के रूप में क्या स्वीकार करता है, जब HTML को वापस पार्स किया जाता है तो इसे कैसे पहचाना जाता है। यह वह जगह है जहां अधिकांश कस्टम संपादक का काम होता है, और जहां GrapesJS के प्रकार और आपके बीच की सीमा खींची जानी होती है।

सही पाने के लिए हस्ताक्षर

editor.Components.addType(प्रकार, विकल्प) AddComponentTypeOptions लेता है — मॉडल, दृश्य, isComponent, विस्तार — ComponentDefinition नहीं। ComponentDefinition एक पेड़ के अंदर एक घोषित नोड का वर्णन करता है: एक घटक के बच्चे, या एक ब्लॉक की सामग्री। ट्यूटोरियल जो ComponentDefinition को addType में पास करते हैं, वे एक पुराने आकार को उद्धृत कर रहे हैं, और इससे आपको जो त्रुटि मिलती है वह स्पष्ट नहीं है।

एसआरसी/संपादक/components.tsts
import type { Editor, Component } from 'grapesjs';

// YOUR domain model. GrapesJS knows nothing about it, and that is the point:
// this is the shape your API, your database and your React props agree on.
export interface HeroContent {
  headline: string;
  subheadline?: string;
  ctaLabel: string;
  ctaHref: string;
}

const HERO_DEFAULTS: HeroContent = {
  headline: 'Your headline',
  ctaLabel: 'Get started',
  ctaHref: '#',
};

// addType takes AddComponentTypeOptions — model / view / isComponent — not a
// ComponentDefinition. Tutorials that pass a ComponentDefinition here are
// describing an API that no longer exists.
export function registerHero(editor: Editor): void {
  editor.Components.addType('hero', {
    isComponent: (el) => el.dataset?.gjsType === 'hero',
    model: {
      defaults: {
        tagName: 'section',
        droppable: false,
        attributes: { 'data-gjs-type': 'hero' },
        traits: [
          { type: 'text', name: 'headline', label: 'Headline' },
          { type: 'text', name: 'ctaLabel', label: 'Button label' },
          { type: 'text', name: 'ctaHref', label: 'Button link' },
        ],
        ...HERO_DEFAULTS,
      },
    },
  });
}

// The bridge back to your model. component.get() is intentionally loose —
// this function is where that looseness stops and HeroContent begins.
export function readHero(component: Component): HeroContent {
  return {
    headline: component.get('headline') ?? HERO_DEFAULTS.headline,
    subheadline: component.get('subheadline'),
    ctaLabel: component.get('ctaLabel') ?? HERO_DEFAULTS.ctaLabel,
    ctaHref: component.get('ctaHref') ?? HERO_DEFAULTS.ctaHref,
  };
}
  • लक्षण सेटिंग पैनल हैं। प्रत्येक प्रविष्टि एक मॉडल फ़ील्ड का नाम देती है, इसलिए पैनल और आपका इंटरफ़ेस कदम से जुड़े रहते हैं।
  • isComponent इस तरह से सहेजे गए पृष्ठ को लोड होने पर पहचाना जाता है। इसके बिना, पुनः लोड करने से आपका कस्टम अनुभाग वापस एक सादे div में बदल जाता है।
  • droppable और draggable बूलियन या चयनकर्ता हैं - यह वह जगह है जहां आप लोगों को एक बटन के अंदर hero छोड़ने से रोकते हैं।

दो प्रकार की प्रणालियाँ, जानबूझकर अलग

GrapesJS प्रकार संपादक का वर्णन करते हैं API। आपके अपने इंटरफेस को आपके उत्पाद के मॉडल का वर्णन करना चाहिए। उन्हें मिलाना लगभग एक सप्ताह तक कुशल लगता है: फिर आपके डेटाबेस को जिस फ़ील्ड की आवश्यकता होती है, उसमें एक घटक विशेषता को छोड़कर रहने के लिए कहीं नहीं होता है, और एक घटक के आंतरिक भाग आपके स्कीमा का हिस्सा बन जाते हैं। ऊपर readHero जैसे फ़ंक्शन को एकमात्र स्थान के रूप में रखें जहां दोनों मिलते हैं - डाउनस्ट्रीम में सब कुछ आपके इंटरफ़ेस को लेता है, न कि Component।

अगले: इसे ब्लॉक शेल्फ पर रखें
चरण 7

7. टाइप करें GrapesJS Blocks

एक ब्लॉक वह है जो बाएं हाथ के शेल्फ में दिखाई देता है और उपयोगकर्ता क्या खींचता है। यह एक घटक नहीं है - यह एक घोषणा है कि क्या सम्मिलित करना है। दोनों को सीधा रखना जल्दी करने लायक है, क्योंकि उनके प्रकार विनिमेय नहीं हैं और त्रुटि संदेश ऐसा नहीं कहता है।

एसआरसी/संपादक/blocks.tsts
import type { Editor, Block, BlockProperties } from 'grapesjs';

// BlockProperties is exported, so the block can be declared away from the
// editor and checked on its own — label, category, media, content.
const heroBlock: BlockProperties = {
  label: 'Hero',
  category: 'Sections',
  media: '<svg viewBox="0 0 24 24"><rect width="24" height="24" /></svg>',
  // A block's content can be a component definition rather than an HTML
  // string, which is how a block and a custom component type stay in sync.
  content: { type: 'hero' },
};

export function addHeroBlock(editor: Editor): Block {
  // Blocks.add(id, props) returns the created Block.
  return editor.Blocks.add('hero', heroBlock);
}

ब्लॉक घोषणा क्या रखती है

परिचय
Blocks.add के लिए पहला तर्क, एक फ़ील्ड नहीं। प्रति संपादक अद्वितीय; एक ही आईडी को फिर से जोड़ने से ब्लॉक बदल जाता है।
लेबल
उपयोगकर्ता शेल्फ पर क्या पढ़ता है। यहां एक फ़ील्ड जो आपकी लोकेल फ़ाइलों में है।
कोटि
शेल्फ़ को समूहीकृत करता है. एक स्ट्रिंग, या एक ऑब्जेक्ट जब आप इसे डिफ़ॉल्ट रूप से संक्षिप्त करना चाहते हैं।
सामग्री
क्या डाला जाता है: एक HTML स्ट्रिंग, या एक घटक परिभाषा। परिभाषा को प्राथमिकता दें - यह ब्लॉक को मार्कअप के स्निपेट के बजाय एक घटक प्रकार से बंधे रखता है।
मीडिया
थंबनेल, इनलाइन एसवीजी के रूप में। <img> का उपयोग करने से आपको कुछ भी नहीं रोकता है, लेकिन इनलाइन एसवीजी संपादक की थीम का अनुसरण करता है।
विशेषताएँ
शेल्फ आइटम पर ही लागू होता है - परीक्षण आईडी और एनालिटिक्स हुक के लिए उपयोगी, सम्मिलित तत्व के लिए नहीं।

Blocks.add बनाया गया Block लौटाता है, ताकि आप इसे कैप्चर कर सकें और बाद में शेल्फ को समायोजित कर सकें - उपयोगकर्ता की योजना में शामिल नहीं होने वाले ब्लॉक को फिर से व्यवस्थित करना, छिपाना या रनटाइम पर श्रेणी लेबल की अदला-बदली करना।

अगले: यह सब एक प्लगइन के रूप में पैकेज करें
चरण 8

8. GrapesJS TypeScript के साथ GrapesJS Plugin बनाएं

एक GrapesJS प्लगइन एक फ़ंक्शन है जो संपादक और एक विकल्प ऑब्जेक्ट प्राप्त करता है। यही कारण है कि प्लगइन्स किसी भी चीज़ के लिए प्राकृतिक इकाई है जिसे आप संपादकों में पुनः उपयोग करना चाहते हैं, किसी अन्य टीम को भेजना चाहते हैं, या बेचना चाहते हैं।

एक आकृति जो विकास से बचती है

प्रति पंजीकरण प्रकार की एक फ़ाइल। इसका कारण साफ-सफाई नहीं है: blocks.ts निर्यात BlockProperties वस्तुओं को निर्यात करता है जो दायरे में बिना किसी संपादक के टाइप-चेक करते हैं, इसलिए उन्हें एक संपादक को बूट किए बिना यूनिट-परीक्षण और पुनः उपयोग किया जा सकता है।

my-grapesjs-plugin/ ├── src/ │ ├── index.ts # the Plugin<Options> function, and only that │ ├── types.ts # the exported Options interface │ ├── blocks.ts # BlockProperties, one per block │ ├── components.ts # editor.Components.addType calls │ └── commands.ts # editor.Commands.add calls ├── tsconfig.json ├── package.json # "types": "dist/index.d.ts" └── README.md
एसआरसी/index.tsts
import type { Editor, Plugin } from 'grapesjs';

// Export the options type. A consumer cannot configure your plugin safely if
// the shape of `options` lives only inside your implementation.
export interface SectionsPluginOptions {
  category?: string;
  blockPrefix?: string;
}

// Plugin<T> is (editor: Editor, config: T) => PluginResult. Typing the
// function as Plugin<SectionsPluginOptions> checks both parameters for you.
const sectionsPlugin: Plugin<SectionsPluginOptions> = (editor, options) => {
  // Defaults belong here, not in the type — an optional field plus a
  // destructured default is what makes the call site free to omit them.
  const { category = 'Sections', blockPrefix = 'sec' } = options;

  editor.Blocks.add(`${blockPrefix}-hero`, {
    label: 'Hero',
    category,
    content: { type: 'hero' },
  });

  editor.Commands.add(`${blockPrefix}:reset`, {
    run(ed: Editor) {
      ed.setComponents('');
    },
  });
};

export default sectionsPlugin;

प्रकार आपको क्या खरीदता है

विकल्प
इंटरफ़ेस निर्यात करें। एक उपभोक्ता जो आपके विकल्पों का आकार नहीं देख सकता है, उसे आपके प्लगइन को कॉन्फ़िगर करने के लिए आपके स्रोत को पढ़ना होगा।
चूक
प्रकार पर वैकल्पिक फ़ील्ड, डिफ़ॉल्ट शरीर में विघटित होता है। इसके बजाय प्रकार में डिफ़ॉल्ट डालने से कॉल साइट पर आवश्यक प्रत्येक फ़ील्ड हो जाती है।
संपादक पैरामीटर
आपके लिए Plugin<T> द्वारा टाइप किया गया। आप जो कुछ भी अंदर पंजीकृत करते हैं - ब्लॉक, घटक प्रकार, कमांड - वास्तविक प्रबंधक हस्ताक्षरों के विरुद्ध जांचा जाता है।
पंजीकरण
Blocks, घटक प्रकार, कमांड और ईवेंट हैंडलर सभी एक ही फ़ंक्शन में जाते हैं। एक प्लगइन जो कॉल टाइम पर कुछ भी पंजीकृत नहीं करता है और किसी ईवेंट की प्रतीक्षा करता है, वह भी ठीक है।

इसे पंजीकृत करना

क्लोजर पास करने से आपके विकल्प कॉल साइट पर टाइप किए जाते हैं। विकल्प - प्लगइन्स में प्लगइन और इसकी सेटिंग्स को pluginsOpts में सूचीबद्ध करना - उन सेटिंग्स को एक ढीले रिकॉर्ड के रूप में टाइप करता है, इसलिए एक गलत वर्तनी वाली कुंजी संकलित होती है और चुपचाप कुछ भी नहीं करती है।

एसआरसी/संपादक/createEditor.tsts
import grapesjs from 'grapesjs';
import sectionsPlugin, { type SectionsPluginOptions } from './my-grapesjs-plugin';

const options: SectionsPluginOptions = { category: 'Marketing' };

grapesjs.init({
  container: '#gjs',
  // Passing a closure keeps the options typed at the call site. The alternative
  // — plugins: [sectionsPlugin] with pluginsOpts — types options as
  // Record<string, any>, so a misspelled key compiles and silently does nothing.
  plugins: [(editor) => sectionsPlugin(editor, options)],
});
अगला: घटक एक प्लगइन जहाज
चरण 9

9. Components के साथ कस्टम TypeScript बनाएं

एक डिज़ाइन-सिस्टम अनुभाग एक घटक नहीं है - यह एक छोटा पेड़ है जिस आकार के लिए आपके उत्पाद का पहले से ही एक नाम है। उस आकार का एक बार वर्णन करना, एक इंटरफ़ेस के रूप में, संपादक, API और रेंडरर को अलग होने से रोकता है।

एक खंड, चार प्रकार

Hero ← one component type, one interface ├── Heading ← extends 'text' ├── Description ← extends 'text' └── Button ← extends 'link', traits: label + href
एसआरसी/संपादक/design-system.tsts
import type { Editor, ComponentDefinition } from 'grapesjs';

// The composed shape, described once. Every layer below — the editor default,
// the API payload, the renderer — is checked against this one interface.
export interface HeroContent {
  headline: string;
  description: string;
  ctaLabel: string;
  ctaHref: string;
}

// ComponentDefinition is what goes *inside* a tree: the children of a
// component, or the `content` of a block. It is not what addType takes.
const heroChildren = (content: HeroContent): ComponentDefinition[] => [
  { type: 'text', tagName: 'h1', content: content.headline },
  { type: 'text', tagName: 'p', content: content.description },
  {
    type: 'link',
    content: content.ctaLabel,
    attributes: { href: content.ctaHref },
  },
];

export function registerDesignSystem(
  editor: Editor,
  defaults: HeroContent
): void {
  editor.Components.addType('hero', {
    model: {
      defaults: {
        tagName: 'section',
        droppable: false,
        // Children are declared, not hand-written as an HTML string, so a
        // renamed field is a compile error rather than a silently stale block.
        components: heroChildren(defaults),
        traits: [
          { type: 'text', name: 'headline', label: 'Headline' },
          { type: 'text', name: 'ctaHref', label: 'Button link' },
        ],
      },
    },
  });
}

क्या टाइप करें और क्या नहीं

सामग्री इंटरफ़ेस
तुम्हारा। शीर्षक, विवरण, कॉल टू एक्शन - वे क्षेत्र जिन्हें एक बाज़ारिया भरता है और आपका API स्टोर।
घटक प्रकार
GrapesJS का। एक बार addType के साथ पंजीकृत, टैग, traits और बच्चों की घोषणा करना।
लक्षण
पुल। प्रत्येक विशेषता मॉडल पर एक फ़ील्ड का नाम देती है, इसलिए आपके इंटरफ़ेस में एक फ़ील्ड का नाम बदलने से विशेषता सूची टूट जानी चाहिए - और डिफ़ॉल्ट के साथ, यह करता है।
बच्चे
ComponentDefinition एक HTML स्ट्रिंग के बजाय ऑब्जेक्ट। एक स्ट्रिंग संकलित करती है चाहे आप उसमें कुछ भी डालें; एक परिभाषा की जाँच की जाती है।
गुण
जहां डेटा-जीजेएस-प्रकार रहता है, जो कि पुनः लोड करने पर isComponent से मेल खाता है।

अदायगी आज कम बग नहीं है - यह है कि छह महीने बाद, HeroContent में एक फ़ील्ड जोड़ने से स्ट्रिंग 'हेडलाइन' के लिए कोडबेस पर खोज के बजाय हर उस स्थान की एक सूची तैयार होती है जिसे बदलना पड़ता है।

अगला: इसे अपने डेटाबेस के अंदर और बाहर निकालें
चरण 10

10. GrapesJS भंडारण और API डेटा टाइप करें

भंडारण वह जगह है जहां दो प्रकार के सिस्टम सबसे परिणामी तरीके से मिलते हैं, क्योंकि यह वह सीमा है जो आपके डेटाबेस में समाप्त होती है। इसे गलत करना बाद में महंगा है; इसे सही करना लगभग बीस लाइनें हैं।

दो आकार, एक नहीं

ProjectData संपादक का अपना JSON है। इसकी आंतरिक संरचना GrapesJS से संबंधित है, संस्करणों के बीच परिवर्तन करती है, और हाथ से माइग्रेट करने के लिए कुछ नहीं है। आपका ProjectRecord एक पंक्ति है: एक आईडी, एक मालिक, एक नाम, एक संस्करण, टाइमस्टैम्प - साथ ही एक कॉलम में वह अपारदर्शी बूँद। इसे स्टोर करें, इसे लोड करें और इसके अंदरूनी हिस्से को अकेला छोड़ दें।

एसआरसी/प्रकार/projects.tsts
import type { ProjectData } from 'grapesjs';

// The editor's own JSON. ProjectData is deliberately open — its internal shape
// is GrapesJS's business and changes between versions, so treat it as opaque:
// store it, load it, never reach into it or migrate it by hand.

// YOUR row. This is the type your API returns and your database stores, and it
// is not a GrapesJS type. Keeping the two apart is what lets you add a column,
// change a version scheme or move providers without touching editor code.
export interface ProjectRecord {
  id: string;
  name: string;
  userId: string;
  version: number;
  updatedAt: string;
  projectData: ProjectData;
}
  1. GrapesJS
  2. Storage API
  3. Application
  4. Database

संपादक प्रोजेक्ट डेटा तैयार करता है। आपका स्टोरेज एडाप्टर एकमात्र कोड है जो दोनों पक्षों को छूता है।

एसआरसी/संपादक/storage.tsts
import grapesjs from 'grapesjs';
import type { Editor, ProjectData } from 'grapesjs';
import type { ProjectRecord } from './types/projects';

export function createEditor(projectId: string): Editor {
  const editor = grapesjs.init({
    container: '#gjs',
    storageManager: {
      // The id of the storage you register below.
      type: 'remote-api',
      autosave: true,
      stepsBeforeSave: 5,
    },
  });

  editor.Storage.add('remote-api', {
    async load(): Promise<ProjectData> {
      const res = await fetch(`/api/projects/${projectId}`);
      // Throwing here is what makes the editor emit storage:error. Returning
      // an empty object instead loses the reader's work without telling them.
      if (!res.ok) throw new Error(`Load failed: ${res.status}`);
      const record = (await res.json()) as ProjectRecord;
      return record.projectData;
    },

    async store(data: ProjectData): Promise<void> {
      const res = await fetch(`/api/projects/${projectId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ projectData: data }),
      });
      if (!res.ok) throw new Error(`Save failed: ${res.status}`);
    },
  });

  editor.on('storage:error', (error) => console.error(error));

  return editor;
}

एडेप्टर को क्या संभालना है

भार
वर्तमान परियोजना के लिए ProjectData लौटाएँ। एक असफल प्रतिक्रिया पर फेंकना वह है जो संपादक को चुपचाप एक खाली कैनवास खोलने के बजाय storage:error का उत्सर्जन करता है।
स्टोर
डेटा को वैसे ही भेजें। बाहर निकलते समय इसे फिर से आकार न दें - आप जो भी छीनते हैं, संपादक लोड पर वापस आने की उम्मीद करता है।
स्वतः सेव
autosave stepsBeforeSave बैचों में परिवर्तन के साथ। प्रत्येक कीस्ट्रोक कोई अनुरोध नहीं है, और नंबर ट्यून करने के लिए आपका है।
संस्करण
आपकी पंक्ति पर एक संस्करण कॉलम, सर्वर-साइड में वृद्धि। रिकॉर्ड का संस्करण करें, कभी भी संपादक का JSON नहीं।
बहु-किरायेदारी
प्रोजेक्ट आईडी एडेप्टर में एक क्लोजर वेरिएबल है, और स्वामित्व सर्वर-साइड की जाँच की जाती है। संपादक के पास उपयोगकर्ता की कोई अवधारणा नहीं है और उसे एक प्राप्त नहीं करना चाहिए।
अगला: संपादक को एक ढांचे के अंदर रखें
चरण 11

11. GrapesJS React और TypeScript के साथ

एक आधिकारिक React आवरण है @grapesjs/react, MIT-लाइसेंस प्राप्त, वर्तमान में 2.0.0 - और यह अपनी स्वयं की घोषणा फ़ाइल भेजता है। यह कैनवास के अंदर React घटकों को प्रस्तुत नहीं करता है; यह संपादक को माउंट करता है और आपको उदाहरण देता है।

ऐप/संपादक/PageEditor.tsxtsx
'use client';

import { useRef } from 'react';
import grapesjs from 'grapesjs';
import type { Editor, ProjectData } from 'grapesjs';
import GjsEditor from '@grapesjs/react';
import 'grapesjs/dist/css/grapes.min.css';

interface PageEditorProps {
  projectId: string;
  onSave: (projectId: string, data: ProjectData) => void;
}

export default function PageEditor({ projectId, onSave }: PageEditorProps) {
  const editorRef = useRef<Editor | null>(null);

  return (
    <GjsEditor
      // Required. The wrapper does not import grapesjs itself — you pass the
      // module (or a CDN URL), which is what lets you control the version.
      grapesjs={grapesjs}
      options={{ height: '100vh', storageManager: false }}
      onEditor={(editor) => {
        editorRef.current = editor;
      }}
      // projectData is typed as ProjectData, so it lines up with the record
      // type your save endpoint expects.
      onUpdate={(projectData) => onSave(projectId, projectData)}
    />
  );
}

grapesjs प्रोप की आवश्यकता है। रैपर जानबूझकर संपादक को आयात नहीं करता है, इसलिए आपके बंडल का संस्करण आपके package.json में वही रहता है - और इसलिए आप इसे इसके बजाय CDN बिल्ड पर इंगित कर सकते हैं।

या बिना आवरण के

रैपर एक सुविधा है, आवश्यकता नहीं। रेफरी के साथ एक useEffect लगभग पंद्रह पंक्तियों में एक ही काम करता है, और यदि आप रैपर का उपयोग करते हैं तो भी यह समझने योग्य है, क्योंकि यह दो नियमों को स्पष्ट करता है: रेफरी की रक्षा करें, और सफाई पर नष्ट करें।

ऐप/संपादक/PageEditor.tsxtsx
'use client';

import { useEffect, useRef } from 'react';
import grapesjs from 'grapesjs';
import type { Editor } from 'grapesjs';
import 'grapesjs/dist/css/grapes.min.css';

export default function PageEditor() {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const editorRef = useRef<Editor | null>(null);

  useEffect(() => {
    // strictNullChecks forces this guard, and it is not ceremony: the ref is
    // null on the first render, before React has attached the div.
    if (!containerRef.current) return;

    const editor = grapesjs.init({
      container: containerRef.current,
      height: '100vh',
      storageManager: false,
    });
    editorRef.current = editor;

    // Without destroy(), React 18's development StrictMode double-mount leaves
    // two editors bound to one container.
    return () => {
      editor.destroy();
      editorRef.current = null;
    };
  }, []);

  return <div ref={containerRef} />;
}
  • कंटेनर रेफरी पहले रेंडर पर शून्य है। strictNullChecks आपको यह कहने पर मजबूर करता है कि फिर क्या होता है।
  • एक सफाई लौटाएं जो destroy() को कॉल करती है। React 18 का विकास StrictMode दो बार माउंट होता है, और इसके बिना आपको एक div में दो संपादक मिलते हैं।
  • रैपर की पीयर रेंज React ^18.0.0 || ^19.0.0 है। React 17 पर आप मैनुअल पथ पर हैं।
संपूर्ण React एकीकरण मार्गदर्शिका के लिए, GrapesJS + React देखें। अगला: सर्वर सीमा के साथ एक ही बात
चरण 12

12. GrapesJS Next.js और TypeScript के साथ

संपूर्ण Next.js प्रश्न एक सीमा है। grapesjs.init को एक वास्तविक DOM तत्व, साथ ही दस्तावेज़ और विंडो की आवश्यकता होती है; एक Server Component में उनमें से कोई भी नहीं है। तो संपादक Client Component में जाता है, और इसके ऊपर की हर चीज़ सर्वर पर रह सकती है।

लाइन कहां जाती है

'use client' संपादक बनाने वाले घटक के शीर्ष पर है, और कहीं भी अधिक नहीं है। इसके ऊपर का पृष्ठ Server Component रहता है: यह पैरा की प्रतीक्षा करता है, सत्र की जांच करता है, प्रोजेक्ट को लोड करता है और सादे प्रॉप्स को पास करता है। यह विभाजन सुरक्षित रखने लायक है, क्योंकि एक फ़ाइल को ऊपर ले जाने से 'use client' चुपचाप आपका डेटा लोड हो रहा है क्लाइंट कोड में बदल जाता है।

ऐप/एडिटर/[आईडी]/एडिटर-क्लाइंट.टीएसएक्सtsx
// app/editor/[id]/editor-client.tsx
'use client';

import { useEffect, useRef } from 'react';
import grapesjs from 'grapesjs';
import type { Editor } from 'grapesjs';
import 'grapesjs/dist/css/grapes.min.css';

export default function EditorClient({ projectId }: { projectId: string }) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const editorRef = useRef<Editor | null>(null);

  // grapesjs.init needs a real element, document and window. Calling it in a
  // module body — or in a Server Component — runs it during the server render,
  // where none of those exist. useEffect only runs in the browser, which is
  // the whole requirement.
  useEffect(() => {
    if (!containerRef.current) return;
    const editor = grapesjs.init({
      container: containerRef.current,
      height: '100vh',
    });
    editorRef.current = editor;
    return () => {
      editor.destroy();
      editorRef.current = null;
    };
  }, [projectId]);

  return <div ref={containerRef} />;
}
ऐप/एडिटर/[आईडी]/पेज.टीएसएक्सtsx
// app/editor/[id]/page.tsx  — a Server Component, no 'use client'
import EditorClient from './editor-client';

interface PageProps {
  params: Promise<{ id: string }>;
}

export default async function EditorPage({ params }: PageProps) {
  const { id } = await params;

  // Auth, data loading and permissions stay on the server, fully typed.
  // Only the editor itself crosses into the client.
  return <EditorClient projectId={id} />;
}
useEffect, मॉड्यूल बॉडी नहीं
सर्वर पर grapesjs आयात करना हानिरहित है - यह init() कॉल कर रहा है जो विफल हो जाता है। useEffect केवल ब्राउज़र में चलता है, जो पूरी आवश्यकता है।
गतिशील आयात वैकल्पिक है
next/dynamic ssr: false के साथ एक बंडल-आकार का निर्णय है, शुद्धता वाला नहीं, और यह Server Component के अंदर उपलब्ध नहीं है। यदि संपादक किसी बड़े पृष्ठ का एक छोटा सा हिस्सा है तो उस तक पहुंचें; इसे ऐसे मार्ग पर छोड़ें जो केवल संपादक है।
CSS
क्लाइंट घटक से grapesjs/dist/css/grapes.min.css आयात करें। इसके बिना कैनवास अनस्टाइल हो जाता है और अनस्टाइल के बजाय टूटा हुआ दिखता है।
सफाई
प्रभाव की वापसी में React: destroy() के समान। रूट ट्रांज़िशन घटक को अनमाउंट करते हैं, और एक संपादक जो अपने कंटेनर को मात देता है, अपने श्रोताओं को लीक करता है।
पूर्ण Next.js बिल्ड के लिए, Next.js पेज बिल्डर गाइड देखें। अगले: Vue और Angular
चरण 13

13. GrapesJS Vue और Angular के साथ

दोनों काम करते हैं, और दोनों मैनुअल React संस्करण के समान आकार का पालन करते हैं: एक टेम्पलेट रेफरी, तत्व मौजूद होने के बाद आरंभीकरण, टियरडाउन पर नष्ट हो जाता है। ढांचा-विशिष्ट यांत्रिकी के पास यहां एक संघनित संस्करण के बजाय अपने स्वयं के गाइड हैं।

दोनों ही मामलों में प्रकार वही हैं जिनका उपयोग यह पृष्ठ कर रहा है: Editor, Component, ProjectData। फ्रेमवर्क बदल जाता है जहां init() कहा जाता है, न कि जो यह लौटाता है वह नहीं।

चरण 14

14. TypeScript उत्पादन के लिए वास्तुकला GrapesJS Editor

ऊपर दी गई हर चीज़ एक फ़ाइल में फिट बैठती है। यह लगभग तीसरे कस्टम घटक पर फिट होना बंद कर देता है, और जो चीज यह तय करती है कि अगला वर्ष सुखद है या नहीं, वह वह है जहां आप अपने एप्लिकेशन और संपादक के बीच सीम डालते हैं।

एक संरचना जो धारण करती है

src/ ├── editor/ # everything that touches the Editor instance │ ├── createEditor.ts # grapesjs.init, one place, returns Editor │ ├── plugins.ts # Plugin<T> registrations │ ├── components.ts # Components.addType calls │ ├── blocks.ts # BlockProperties definitions │ ├── commands.ts # Commands.add calls │ └── storage.ts # Storage.add, ProjectData in and out │ ├── types/ │ ├── editor.ts # aliases over GrapesJS types you use a lot │ ├── components.ts # HeroContent and friends — YOUR model │ ├── projects.ts # ProjectRecord — your database row │ └── api.ts # request/response shapes │ └── app/ # imports from types/, never from editor/ internals

एक सीम, घोषित

एप्लिकेशन कोड को सीधे 'grapesjs' से आयात नहीं करना चाहिए। इसे एक एकल मॉड्यूल दें जो आपके उत्पाद के बारे में वैध रूप से जानने वाले मुट्ठी भर संपादक प्रकारों को फिर से निर्यात करता है, उन प्रबंधकों को उपनाम देता है जो निर्यात नहीं किए जाते हैं, और संकीर्ण इंटरफ़ेस की घोषणा करता है जिस पर आपका UI वास्तव में निर्भर करता है। फिर एक टूलबार बटन उस इंटरफ़ेस को लेता है, न कि पूरे Editor - और दुर्घटना से भी संपादक आंतरिक तक नहीं पहुंच सकता है।

एसआरसी/प्रकार/editor.tsts
// src/types/editor.ts — the single seam between your app and the editor.
import type { Editor, ProjectData } from 'grapesjs';

// Re-export what your application is allowed to know about.
export type { Editor, ProjectData };

// Manager classes are not exported by name; alias them here once so no other
// file has to remember that.
export type BlockManager = Editor['Blocks'];
export type StorageManager = Editor['Storage'];

// The surface your UI actually depends on. Application code takes this, not a
// full Editor, so a toolbar button cannot quietly reach into editor internals.
export interface EditorFacade {
  getHtml(): string;
  getCss(): string;
  save(): Promise<void>;
  destroy(): void;
}
लेयरिंग

परतें, और किस तरह से निर्भरताएं इंगित करती हैं

शीर्ष पर आपका आवेदन, बीच में आपके प्रकार, नीचे संपादक। निर्भरताएं नीचे की ओर इशारा करती हैं और कभी भी वापस नहीं आती हैं।

  1. आवेदन

    तुम्हारा। GrapesJS के बारे में कुछ नहीं जानता।

    • रूटिंग
    • प्रमाणीकरण
    • आवेदन की स्थिति
    • आपका UI
  2. प्रकार

    सीवन। एकमात्र स्थान दोनों दुनिया का नाम रखा गया है।

    • डोमेन मॉडल
    • परियोजना रिकॉर्ड
    • API अनुबंध
  3. Editor परत

    तुम्हारा। एकमात्र कोड जो संपादक से आयात करता है।

    • createEditor
    • प्लगइन्स
    • Component प्रकार
    • भंडारण एडाप्टर
  4. GrapesJS

    संपादक। पैकेज द्वारा टाइप किया गया।

    • कैंवस
    • प्रबंधकों
    • आयोजन
इसे किसी और के उत्पाद में एम्बेड करना?
पूरी तस्वीर

15. SaaS पेज Builder के लिए TypeScript आर्किटेक्चर

एक पेज-बिल्डर उत्पाद ज्यादातर पेज बिल्डर नहीं होता है। GrapesJS इस श्रृंखला में एक बॉक्स को कवर करता है; बाकी एक एप्लिकेशन है जिसे आप वैसे भी लिखने जा रहे थे, और उनके बीच जुड़ाव टाइप करना ही यह मार्गदर्शिका का निर्माण कर रही है।

  1. SaaS application
  2. Authentication
  3. GrapesJS editor
  4. Typed components
  5. Typed plugins
  6. Storage API
  7. Database
  8. Publishing

GrapesJS संपादन सतह का मालिक है। प्रमाणीकरण, भंडारण, किरायेदारी, बिलिंग और प्रकाशन आपका है।

पूरी तस्वीर

किसका मालिक है

GrapesJS संपादन सतह का मालिक है। प्रमाणीकरण, भंडारण, किरायेदारी, बिलिंग और प्रकाशन आपका है।

Your product

आप प्रदान करते हैं

हर उस चीज के बारे में संपादक की कोई राय नहीं है।

  • खाते, सत्र और अनुमतियां
  • किरायेदारी और प्रति-योजना सीमाएँ
  • डेटाबेस और उसके माइग्रेशन
  • प्रकाशन, डोमेन और होस्टिंग
  • बिलिंग और उपयोग
GrapesJS

GrapesJS प्रदान करता है

कैनवास के अंदर सब कुछ, पैकेज द्वारा टाइप किया गया।

  • कैनवास और ड्रैग-एंड-ड्रॉप
  • Blocks, शैलियाँ, परतें, traits, संपत्ति
  • HTML और CSS आउटपुट
  • JSON के माध्यम से परियोजना Storage Manager
  • Component प्रकार, प्लगइन्स और कमांड

संपादक आपके उत्पाद का एक घटक है, इसका विकल्प नहीं।

चरण 16

16. सामान्य GrapesJS TypeScript गलतियाँ

ग्यारह विफलताएं जो बार-बार सामने आती हैं, उनमें से अधिकांश सामान्य रूप से TypeScript के बजाय इस जोड़ी के लिए विशिष्ट हैं। हर एक लक्षण है जिसके साथ आप मेल खा सकते हैं और वह परिवर्तन जो इसे ठीक करता है।

@types/grapesjs स्थापित करना

लक्षण

npm install fails E404 के साथ, या एक ट्यूटोरियल आपको इसे जोड़ने के लिए कहता है और आप मान लेते हैं कि आपकी रजिस्ट्री टूट गई है।

ठीक करना

इसे हटा दें। प्रकार grapesjs के अंदर ही हैं, पैकेज के प्रकार फ़ील्ड द्वारा संदर्भित। कोई अलग प्रकार का पैकेज नहीं है और वर्तमान लाइन के लिए एक भी नहीं है।

संपादक को किसी भी रूप में टाइप करना

लक्षण

संपादक को दें: कोई भी, आमतौर पर सेटअप के दौरान एक त्रुटि को शांत करने के लिए जोड़ा जाता है, और कभी नहीं हटाया जाता है।

ठीक करना

Editor 'grapesjs' से। जड़ में एक भी हर प्रबंधक, हर ईवेंट पेलोड और हर निर्यात कॉल के लिए फैलता है - आप TypeScript की संकलन-समय लागत रखते हैं और सभी लाभ खो देते हैं।

प्लगइन विकल्पों को बिना टाइप किए छोड़ना

लक्षण

एक प्लगइन विकल्प लेता है: कोई भी या रिकॉर्ड<string, unknown>; उपभोक्ताओं का अनुमान है कि फ़ील्ड नाम और टाइपो कुछ नहीं करते हैं।

ठीक करना

एक विकल्प इंटरफ़ेस घोषित करें और निर्यात करें, फिर फ़ंक्शन को Plugin<YourOptions> के रूप में टाइप करें। फिर कॉल साइट सहित दोनों मापदंडों की जाँच की जाती है।

भ्रमित करने वाला Block और Component

लक्षण

एक Block पास करना जहां एक Component की उम्मीद है, या एक ब्लॉक को स्टाइल करने की कोशिश करना और इसे ढूंढना कोई शैली नहीं है।

ठीक करना

एक ब्लॉक एक शेल्फ प्रविष्टि है जो बताती है कि क्या डालना है। एक घटक कैनवास में एक नोड है। Blocks.add BlockProperties लेता है; Components.addType AddComponentTypeOptions लेता है।

ComponentDefinition को जोड़ने के लिए पास करना

लक्षण

एक घटक प्रकार पंजीकृत होता है लेकिन एक सादे div की तरह व्यवहार करता है - कोई traits नहीं, कोई प्रतिबंध नहीं।

ठीक करना

addType AddComponentTypeOptions लेता है: मॉडल, दृश्य, isComponent, विस्तार। ComponentDefinition एक पेड़ के अंदर एक नोड का वर्णन करता है - एक घटक के बच्चे, या एक ब्लॉक की सामग्री।

यह मानते हुए कि प्रत्येक घटना में समान पेलोड है

लक्षण

component:add के लिए लिखे गए हैंडलर का पुनः उपयोग component:remove के लिए किया जाता है और दूसरा तर्क अपरिभाषित होता है।

ठीक करना

पेलोड प्रति घटना भिन्न होते हैं और प्रकार पहले से ही ऐसा कहते हैं। अनुमान आपको किसी अन्य हैंडलर से एनोटेट करने के बजाय पैरामीटर देता है।

आंतरिक संपादक के लिए डेटाबेस मॉडल युग्मन

लक्षण

आपके ProjectRecord में संपादक के JSON के अंदर फ़ील्ड को मिरर करने वाले कॉलम हैं, और GrapesJS अपग्रेड का अर्थ है माइग्रेशन।

ठीक करना

ProjectData को अपारदर्शी मानें। एक कॉलम इसे रखता है; आप जिस कुछ भी पर क्वेरी करते हैं - मालिक, नाम, संस्करण, टाइमस्टैम्प - उसके बगल में रहता है, उसके अंदर नहीं।

अशक्त संपादक संदर्भों को अनदेखा करना

लक्षण

"शून्य के गुणों को नहीं पढ़ सकता" एक तेज़ नेविगेशन, एक गर्म पुनः लोड, या एक मार्ग के पहले रेंडर पर।

ठीक करना

Editor | null का उपयोग करें, और शून्य को संभालें। रेफरी पर गैर-शून्य दावे समस्या को आपके टर्मिनल से आपके त्रुटि ट्रैकर पर ले जाते हैं।

पूर्व-प्रकार ट्यूटोरियल का पालन करना

लक्षण

नामित आयात जो हल नहीं करते हैं, प्रबंधक विधियाँ जो मौजूद नहीं हैं, एक संपादक संस्करण जो कभी प्रकाशित नहीं किया गया था।

ठीक करना

किसी ब्लॉग पोस्ट के बजाय अपने node_modules में घोषणा फ़ाइल के विरुद्ध API की जाँच करें। कोई GrapesJS v1.x नहीं है; वर्तमान रिलीज़ 0.23.6 है।

पैकेजों में संस्करणों का मिश्रण

लक्षण

रैपर का Editor और आपका Editor समान दिखते हैं लेकिन संरचनात्मक रूप से असंगत हैं, और त्रुटि में दो रास्तों का उल्लेख है।

ठीक करना

पेड़ में एक grapesjs। npm ls grapesjs के साथ जांचें - एक प्लगइन के तहत एक नेस्टेड कॉपी सामान्य कारण है।

अधिक व्यापक कस्टम इंटरफेस

लक्षण

एक इंटरफ़ेस जो आधे संपादक API को फिर से घोषित करता है ताकि आप इसे चारों ओर पास कर सकें, हर रिलीज में वास्तविक प्रकारों से बहते हुए।

ठीक करना

उपनाम: जो मौजूद है - Editor['Blocks'] - और केवल संकीर्ण मुखौटा को अपनी UI आवश्यकता की घोषणा करें। संपादक के API को अपने स्वयं के प्रकारों में पुनः स्थापित करना वह रखरखाव है जिसके लिए आपको साइन अप करने की आवश्यकता नहीं है।

इनमें से कोई भी TypeScript समस्या नहीं है। वे ऐसे स्थान हैं जहां संपादक का मॉडल और आपके उत्पाद का मॉडल एक-दूसरे के लिए भ्रमित हो जाते हैं, और टाइप सिस्टम केवल वही है जो भ्रम को जल्दी दिखाई देता है।

चरण 17

17. GrapesJS TypeScript त्रुटियों का निवारण

चार त्रुटि आकृतियाँ लगभग सब कुछ कवर करती हैं। प्रत्येक मामले में उपयोगी कदम किसी भी तक पहुंचने के बजाय घोषणा फ़ाइल को node_modules में देखना है - उत्तर वहां है, और कोई भी केवल प्रश्न को स्थगित कर देता है।

मॉड्यूल 'grapesjs' या इसके संगत प्रकार की घोषणाएँ नहीं ढूँढ सकता

आप देख सकते हैं

आयात लाइन पर TS2307, भले ही पैकेज स्पष्ट रूप से स्थापित हो और संपादक रनटाइम पर ठीक चलता हो।

जाँच

आपका TypeScript संस्करण पहले। 5.0 से नीचे घोषणा फ़ाइल को पार्स नहीं किया जा सकता है और विफलता को एक लापता मॉड्यूल के रूप में रिपोर्ट किया जाता है - वास्तव में भ्रामक संदेश। फिर moduleResolution: यह bundler, node16 या nodenext होना चाहिए, क्लासिक नहीं। @types/grapesjs जोड़ने से मदद नहीं मिलेगी; वह पैकेज मौजूद नहीं है।

मॉड्यूल 'grapesjs' का कोई निर्यात सदस्य 'X' नहीं है

आप देख सकते हैं

TS2614 एक नाम पर जिसे आप घोषणा फ़ाइल में देख सकते हैं, अक्सर StorageManager या BlockManager।

जाँच

प्रबंधक कक्षाएं घोषित की जाती हैं लेकिन निर्यात नहीं की जाती हैं। अनुक्रमित-एक्सेस उपनाम का उपयोग करें - Editor['Storage'], Editor['Blocks'], Editor['Components'] - जो एक ही वर्ग में हल हो जाता है। यदि नाम कुछ और है, तो grep node_modules/grapesjs/dist/index.d.ts: यदि यह नहीं है, तो यह पुराने संस्करण से संबंधित है।

प्रकार का तर्क ... पैरामीटर के लिए असाइन करने योग्य नहीं है

आप देख सकते हैं

एक ईवेंट हैंडलर, एक addType कॉल, या एक ब्लॉक घोषणा जो एक ट्यूटोरियल से सटीक रूप से मेल खाती है और अभी भी संकलित नहीं होगी।

जाँच

हस्ताक्षर, घोषणा फ़ाइल में। ईवेंट प्रति नाम अलग-अलग पेलोड ले जाते हैं; addType ComponentDefinition के बजाय AddComponentTypeOptions लेता है। अपने संपादक में विधि को होवर करें - वास्तविक हस्ताक्षर वहीं है, और यह आमतौर पर आपके द्वारा कॉपी किए गए लेख से अलग आकार का होता है।

दो असंगत Editor प्रकार

आप देख सकते हैं

एक React या Next.js बिल्ड जहां रैपर के Editor और आपका एकजुट होने से इनकार करते हैं, और संदेश दो node_modules पथों को नाम देता है।

जाँच

डुप्लिकेट इंस्टॉल करता है। npm ls grapesjs दूसरी प्रति दिखाएगा, जिसे आमतौर पर एक संकीर्ण सहकर्मी सीमा के साथ एक प्लगइन द्वारा खींचा जाता है। संस्करणों को डुप्लिकेट या संरेखित करें; रैपर की अपनी सहकर्मी सीमा ^0.22.5 है।

फ्रेमवर्क-विशिष्ट प्रकार की त्रुटियों के लिए, React और Next.js मार्गदर्शिकाएँ इस पृष्ठ की तुलना में अधिक गहराई तक जाती हैं।

चरण 18

18. GrapesJS + TypeScript अनुकूलता

सटीक संस्करण, रजिस्ट्री के खिलाफ और स्थापित घोषणा फ़ाइल के खिलाफ जाँच की गई। विशेष रूप से TypeScript फर्श को प्रत्येक रिलीज के खिलाफ संकलित करके मापा गया था, जो कि चेंजलॉग से अनुमान नहीं लगाया गया था।

पैकेजसत्यापित किया गयाइसका क्या मतलब है
grapesjs0.23.6अपने स्वयं के प्रकार dist/index.d.ts पर भेजता है। कोई अलग प्रकार का पैकेज मौजूद नहीं है।
typescript>= 5.0मंजिल। 4.9 और नीचे घोषणा फ़ाइल को पार्स नहीं कर सकते हैं, और इसे लापता मॉड्यूल के रूप में रिपोर्ट नहीं कर सकते हैं।
typescript7.0.2वर्तमान रिलीज़, और इस गाइड के नमूने जिस संस्करण के साथ संकलित किए गए थे। 5.0 से सब कुछ काम करता है।
@grapesjs/react2.0.0आधिकारिक React रैपर, MIT-लाइसेंस प्राप्त, अपने स्वयं के बंडल प्रकारों के साथ।
react^18.0.0 || ^19.0.0रैपर की React पीयर रेंज। React 17 पर, संपादक को useEffect के साथ मैन्युअल रूप से प्रारंभ करें।
grapesjs (peer)^0.22.5रैपर की grapesjs पीयर रेंज - इतनी चौड़ी कि वर्तमान कोर इसे संतुष्ट करता है।
node>=20.9.0GrapesJS एक ब्राउज़र लाइब्रेरी है और घोषित करता है कि कोई इंजन फ़ील्ड नहीं है। आप वास्तव में जिस मंजिल से टकराते हैं वह आपके ढांचे से आता है; Next.js 16.3.4 इसकी आवश्यकता है।

registry.npmjs.org और node_modules/अंगूर/dist/index.d.ts के खिलाफ सत्यापित 2026-09-03। इस पृष्ठ पर प्रत्येक कोड नमूना प्रकाशन से पहले सख्त मोड के तहत इन संस्करणों के खिलाफ संकलित किया गया था।

यहां कोई "प्रत्येक TypeScript संस्करण के साथ काम करता है" नहीं है, क्योंकि यह सच नहीं है: 5.0 एक कठोर मंजिल है और इसके नीचे विफलता मोड इतना भ्रमित करने वाला है कि यह सटीक रूप से बताने लायक है।

चरण 19

19. GrapesJS-संगत प्लगइन्स के साथ TypeScript बढ़ाएं

एक बार जब आप कोर API को समझ लेते हैं, तो प्लगइन्स आपको हर सुविधा को खरोंच से बनाने की आवश्यकता के बिना अतिरिक्त कार्यक्षमता प्रदान कर सकते हैं। ये GJS.Market पर वर्तमान लिस्टिंग हैं, जिन्हें टाइप की गई सतह के किस हिस्से को छूता है, इसके आधार पर समूहीकृत किया जाता है।

एक बात यह पृष्ठ आपको नहीं बताएगा: इनमें से कोई भी लिस्टिंग बंडल TypeScript घोषणाओं का विज्ञापन नहीं करती है, इसलिए प्रकार के समर्थन को असत्यापित मानें और प्लगइन के स्वयं के README की जांच करें। इस बात की परवाह किए बिना कि प्लगइन को प्राप्त होने वाला संपादक कोर पैकेज द्वारा टाइप किया जाता है - इसलिए किसी भी प्लगइन के आसपास आपके एकीकरण कोड की जाँच की जाती है, तब भी जब प्लगइन स्वयं सादा जावास्क्रिप्ट हो।

चरण 20

20. अपना खुद का Plugin बनाएं या किसी मौजूदा का उपयोग करें?

लाइन कठिनाई के बारे में नहीं है। यह इस बारे में है कि क्या व्यवहार आपके उत्पाद के लिए विशिष्ट है - क्योंकि यही तय करता है कि इसे दो साल में किसे बनाए रखना है।

माँगअपने आप को बनाएंप्लगइन का उपयोग करें
आपके व्यवसाय के लिए विशिष्ट व्यवहारहाँ - कोई और इसे नहीं बनाएगा
सामान्य संपादक कार्यक्षमताहाँ - पहले ही हल हो चुका है
कोड का पूर्ण नियंत्रणहाँहां, ओपन-सोर्स प्लगइन्स के लिए
पहले काम करने वाले संस्करण का प्रयासउच्चतरनिचला प्रारंभिक बिंदु
इसका रखरखाव कौन करता हैआपकी टीमPlugin लेखक, साथ ही आपका एकीकरण
आप इसे कितनी दूर तक बदल सकते हैंजहां तक आप चाहेंप्लगइन पर निर्भर करता है

व्यवहार में अधिकांश संपादक दोनों हैं: प्रत्येक संपादक को आवश्यक भागों के लिए मुट्ठी भर प्लगइन्स, और उन भागों के लिए आपके स्वयं के टाइप किए गए घटक प्रकार जो उत्पाद को आपका बनाते हैं।

अपना रास्ता चुनें

आपका स्टैक क्या है?

इस पृष्ठ पर प्रकार हर जगह समान हैं। क्या परिवर्तन होता है जहां आप init() कहते हैं और आप कैसे सफाई करते हैं।

जारी रखो

सीखना जारी रखें GrapesJS

आगे कहां जाना है, यह इस बात पर निर्भर करता है कि आप अभी भी संपादक सीख रहे हैं, इसे एक ढांचे में जोड़ रहे हैं, या इसके चारों ओर एक उत्पाद बना रहे हैं।

कस्टम विकास

उत्पादन GrapesJS Editor का निर्माण?

यदि आर्किटेक्चर अनुभाग वह है जहां आपका प्रोजेक्ट वास्तव में है, तो शेष कार्य आमतौर पर संपादक सुविधाओं के बजाय एकीकरण होता है। हम यही करते हैं।

  • TypeScript प्लगइन्स
  • कस्टम घटक प्रकार
  • React एकीकरण
  • Next.js एकीकरण
  • भंडारण और API एकीकरण
  • SaaS संपादक
  • व्हाइट-लेबल संपादक
  • कस्टम संपादक UI
  • पुराने संस्करणों से माइग्रेशन
  • उत्पादन वास्तुकला की समीक्षा
GrapesJS विशेषज्ञ से बात करें
प्रश्न

अक्सर पूछे जाने वाले प्रश्न

क्या GrapesJS TypeScript का समर्थन करता है?

हाँ। GrapesJS 0.23.6 पैकेज के साथ एक घोषणा फ़ाइल प्रकाशित करता है और इसे अपने स्वयं के प्रकार फ़ील्ड से संदर्भित करता है, इसलिए पैकेज स्थापित होते ही आयात प्रकार काम करता है। प्रकार संपादक इंस्टेंस, उसके प्रबंधकों, घटकों, ब्लॉकों, traits, ईवेंट और प्रोजेक्ट डेटा को कवर करते हैं।

क्या GrapesJS में TypeScript परिभाषाएँ शामिल हैं?

हाँ index.d.ts पैकेज के अंदर dist/index.d.ts पर। आप इसे सीधे node_modules में पढ़ सकते हैं, जो आपके द्वारा वास्तव में इंस्टॉल किए गए संस्करण के विरुद्ध इस पृष्ठ पर किसी भी API प्रश्न की जांच करने का सबसे विश्वसनीय तरीका है।

क्या मुझे @types/grapesjs की आवश्यकता है?

नहीं, और आप इसे स्थापित नहीं कर सकते: पैकेज npm पर प्रकाशित नहीं होता है और इंस्टॉल 404 के साथ विफल हो जाता है। यदि कोई ट्यूटोरियल आपको इसे जोड़ने के लिए कहता है, तो वह ट्यूटोरियल बंडल किए गए प्रकारों से पहले का है और इसकी अन्य सलाह शायद पुरानी भी है।

मैं GrapesJS को TypeScript के साथ कैसे स्थापित करूं?

npm install grapesjs. वह पूरी स्थापना है - एक निर्भरता, प्रकार शामिल हैं। फिर रनटाइम मान के लिए 'grapesjs' से grapesjs और प्रकारों के लिए 'grapesjs' से import type { Editor } आयात करें।

मैं GrapesJS संपादक कैसे टाइप करूं?

grapesjs.init() एक Editor लौटाता है, इसलिए अनुमान पहले से ही इसे सही करता है। जहां यह मायने रखता है वह उदाहरण को पकड़ रहा है: इसे रेफरी या क्लास फ़ील्ड में Editor | null के रूप में टाइप करें, क्योंकि संपादक वास्तव में माउंट करने से पहले या नष्ट करने के बाद मौजूद नहीं है, और strictNullChecks हर कॉल साइट को इसे संभालता है।

मैं GrapesJS घटक कैसे टाइप करूं?

Component कैनवास नोड है। ComponentDefinition एक पेड़ के अंदर एक घोषित नोड का वर्णन करता है - एक घटक के बच्चे, या एक ब्लॉक की सामग्री। एक नए प्रकार को पंजीकृत करने के लिए editor.Components.addType(प्रकार, विकल्प) का उपयोग किया जाता है, जिसमें AddComponentTypeOptions लगता है: मॉडल, दृश्य, isComponent और विस्तार।

मैं GrapesJS ब्लॉक कैसे टाइप करूं?

BlockProperties निर्यात किया जाता है, इसलिए एक ब्लॉक को अपने स्वयं के मॉड्यूल में घोषित किया जा सकता है और दायरे में एक संपादक के बिना जांचा जा सकता है। editor.Blocks.add(आईडी, प्रॉप्स) उस ऑब्जेक्ट को लेता है और बनाए गए Block लौटाता है।

मैं GrapesJS के साथ TypeScript घटनाओं को कैसे संभालूं?

editor.on ईवेंट के नाम पर सामान्य है और इससे कॉलबैक हस्ताक्षर प्राप्त करता है, इसलिए आपको शायद ही कभी मापदंडों को एनोटेट करना चाहिए। ध्यान दें कि ईवेंट का नाम एक ओपन स्ट्रिंग यूनियन है इसलिए प्लगइन्स अपने स्वयं के ईवेंट को परिभाषित कर सकते हैं - जिसका अर्थ है कि एक कोर ईवेंट नाम में एक टाइपो अभी भी संकलित होता है और बस कभी भी फायर नहीं होता है।

मैं TypeScript GrapesJS प्लगइन कैसे बनाऊं?

एक प्लगइन एक फ़ंक्शन है जो संपादक और एक विकल्प ऑब्जेक्ट लेता है। एक विकल्प इंटरफ़ेस निर्यात करें और फ़ंक्शन को Plugin<YourOptions> के रूप में टाइप करें - दोनों मापदंडों की फिर जाँच की जाती है, और उपभोक्ता देख सकते हैं कि आपके स्रोत को पढ़े बिना इसे कैसे कॉन्फ़िगर किया जाए।

क्या मैं GrapesJS के साथ कस्टम TypeScript घटक बना सकता हूँ?

हां, और यह वह जगह है जहां प्रकार सबसे अधिक भुगतान करते हैं। सामग्री के आकार को अपने स्वयं के इंटरफ़ेस के रूप में वर्णित करें, घटक प्रकार को addType के साथ पंजीकृत करें, और उस इंटरफ़ेस पर traits नाम फ़ील्ड को दें - इसलिए किसी फ़ील्ड सतहों का नाम बदलकर उत्पादन में एक रिक्त अनुभाग के बजाय एक संकलन त्रुटि के रूप में करें।

क्या मैं GrapesJS का उपयोग React और TypeScript के साथ कर सकता हूँ?

हाँ। @grapesjs/react 2.0.0 आधिकारिक आवरण है, MIT-लाइसेंस प्राप्त, अपने स्वयं के बंडल प्रकारों के साथ; इसके लिए आपको प्रोप के रूप में grapesjs पास करना होगा। इसकी React पीयर रेंज ^18.0.0 || ^19.0.0 है। React 17 पर, या यदि आप कोई रैपर पसंद नहीं करते हैं, तो रेफरी और destroy() क्लीनअप के साथ useEffect वही काम करता है।

क्या मैं GrapesJS का उपयोग Next.js और TypeScript के साथ कर सकता हूँ?

हाँ। संपादक बनाने वाले घटक पर 'use client' रखें और कहीं भी ऊपर नहीं, और grapesjs.init को useEffect के अंदर कॉल करें - इसे एक वास्तविक तत्व, दस्तावेज़ और विंडो की आवश्यकता होती है, जिनमें से कोई भी सर्वर रेंडर के दौरान मौजूद नहीं होता है। इसके ऊपर का पृष्ठ Server Component रह सकता है और सर्वर पर डेटा लोड करना जारी रख सकता है।

क्या मैं GrapesJS का उपयोग Vue और TypeScript के साथ कर सकता हूँ?

हाँ: एक टेम्पलेट रेफरी, onMounted प्रारंभ करने के लिए, onBeforeUnmount नष्ट करने के लिए। Editor को ref() या प्रतिक्रियाशील() से बाहर रखें - इसे लपेटने से Vue प्रॉक्सी एक ऐसी वस्तु बन जाती है जो अपने स्वयं के आंतरिक का प्रबंधन करती है। कोई आधिकारिक Vue आवरण नहीं है।

क्या मैं GrapesJS का उपयोग Angular और TypeScript के साथ कर सकता हूँ?

हाँ: कंटेनर के लिए @ViewChild, ngAfterViewInit शुरू करने के लिए, ngOnDestroy को फाड़ने के लिए, और runOutsideAngular ताकि संपादक का ईवेंट लूप परिवर्तन का पता लगाने को प्रेरित न करे। कोई आधिकारिक Angular आवरण नहीं है; npm पर पैकेज तृतीय-पक्ष हैं।

क्या मैं GrapesJS को TypeScript बैकएंड से कनेक्ट कर सकता हूँ?

हाँ Storage Manager के माध्यम से, लोड और स्टोर फ़ंक्शंस के साथ एक स्टोरेज पंजीकृत करके जो आपके API को कॉल करता है। दो प्रकारों को अलग रखें: ProjectData संपादक का JSON है और इसे अपारदर्शी रूप से संग्रहीत किया जाना चाहिए, जबकि आपके स्वयं के रिकॉर्ड प्रकार में आईडी, मालिक, नाम, संस्करण और टाइमस्टैम्प होते हैं जिन पर आप वास्तव में क्वेरी करते हैं।

मुझे TypeScript-संगत GrapesJS प्लगइन्स कहां मिल सकते हैं?

GJS.Market कैटलॉग 100+ GrapesJS प्लगइन्स को सूचीबद्ध करता है। ध्यान दें कि अलग-अलग लिस्टिंग वर्तमान में बंडल प्रकार की घोषणाओं का विज्ञापन नहीं करती हैं, इसलिए प्रत्येक प्लगइन के README की जांच करें - लेकिन प्लगइन को प्राप्त होने वाला संपादक ऑब्जेक्ट किसी भी तरह से कोर पैकेज द्वारा टाइप किया जाता है, इसलिए इसके चारों ओर आपका अपना एकीकरण कोड अभी भी चेक किया जाता है।
निर्माण शुरू करें

GrapesJS TypeScript के साथ अपना GrapesJS Editor बनाएं

टाइप किए गए GrapesJS API से शुरुआत करें, अपने स्वयं के घटक और प्लगइन्स बनाएं, अपने एप्लिकेशन इंफ्रास्ट्रक्चर को कनेक्ट करें, और जब आपके उत्पाद को अधिक कार्यक्षमता की आवश्यकता हो तो संपादक का विस्तार करें।

सीखना

ट्यूटोरियल शुरू करें

पैकेज स्थापित करें, संपादक टाइप करें और कुछ ही मिनटों में एक कार्यशील टाइप किया हुआ सेटअप प्राप्त करें।

ट्यूटोरियल शुरू करें
विस्तार

प्लगइन्स का अन्वेषण करें

स्टोरेज एडेप्टर, घटक प्रकार और डेवलपर टूलींग पहले से ही GrapesJS के लिए बनाया गया है।

प्लगइन्स का अन्वेषण करें
निर्माण

कस्टम विकास प्राप्त करें

टाइप किए गए प्लगइन्स, फ्रेमवर्क एकीकरण और उत्पादन वास्तुकला, आपके साथ बनाया गया।

कस्टम विकास प्राप्त करें

TypeScript GrapesJS को सुरक्षित नहीं बनाता है। एक फ़ाइल से आगे निकलने के बाद यह एक अनुकूलित GrapesJS संपादक को बनाए रखने योग्य बनाता है।