आप प्रदान करते हैं
हर उस चीज के बारे में संपादक की कोई राय नहीं है।
- खाते, सत्र और अनुमतियां
- किरायेदारी और प्रति-योजना सीमाएँ
- डेटाबेस और उसके माइग्रेशन
- प्रकाशन, डोमेन और होस्टिंग
- बिलिंग और उपयोग
TypeScript के साथ GrapesJS का उपयोग करना सीखें, टाइप किए गए संपादक एपीआई और ईवेंट के साथ काम करें, कस्टम घटक और प्लगइन्स बनाएं, स्टोरेज कनेक्ट करें और GrapesJS को React, Next.js, Vue या Angular एप्लिकेशन में एकीकृत करें।
GrapesJS 0.23.6 Dist/index.d.ts पर अपनी स्वयं की घोषणा फ़ाइल प्रकाशित करता है, जिसे पैकेज के अपने प्रकार फ़ील्ड से संदर्भित किया गया है। grapesjs स्थापित करने से आपको संपादक और उसके प्रकार एक निर्भरता में मिलते हैं, इसलिए 'Editor' से grapesjs आयात करना बिना किसी अतिरिक्त सेटअप और बिना किसी दूसरे पैकेज के हल हो जाता है।
प्रकार क्या कवर करते हैं संपादक की API सतह - संपादक उदाहरण, इसके प्रबंधक, घटक, ब्लॉक, ईवेंट और प्रोजेक्ट डेटा। वे आपके उत्पाद के अपने मॉडल का वर्णन नहीं करते हैं, और यह मार्गदर्शिका काफी हद तक उन दो चीजों को अलग रखने के बारे में है।
इसे स्थापित करें और शुरू करेंबारह चरण, क्रम में। प्रत्येक उस अनुभाग से लिंक करता है जो इसे कवर करता है, ताकि आप शुरू कर सकें कि आपका प्रोजेक्ट वास्तव में कहां है।
एक पैकेज है। प्रकार इसके साथ आते हैं, इसलिए आपके devDependencies में कोई दूसरा इंस्टॉल और कोई @types प्रविष्टि नहीं है।
npm install grapesjs@types/grapesjs बहिष्कृत, अधिक्रमित या वैकल्पिक नहीं है - यह npm रजिस्ट्री से अनुपस्थित है। इसे चलाने से 404 मिलता है, और यदि आप इसे एक पुराने ट्यूटोरियल में देखते हैं जो एक विश्वसनीय संकेत है तो उस ट्यूटोरियल के बाकी हिस्से बंडल प्रकारों से भी पहले का है।
# Don't. This package is not published — npm returns E404.
npm install --save-dev @types/grapesjsgrapesjs अपने आप में एक मान है: आप grapesjs.init() कहते हैं। Editor, Component और Block प्रकार हैं: वे केवल संकलन के दौरान मौजूद होते हैं। उन्हें import type के साथ चिह्नित करना इसे स्पष्ट करता है, और गारंटी देता है कि आयात आपके बंडल में खींचे जाने के बजाय मिटा दिया गया है - जो फ्रेमवर्क कोड में सबसे ज्यादा मायने रखता है, जहां संपादक का एक आवारा रनटाइम आयात इसे सर्वर रेंडर में खींच सकता है।
// 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';आपको GrapesJS के लिए एक विशेष कॉन्फ़िगरेशन की आवश्यकता नहीं है। आपको चार विकल्पों को सही ढंग से सेट करने की आवश्यकता है - आपका बाकी tsconfig जो कुछ भी आपका प्रोजेक्ट पहले से उपयोग करता है वह रह सकता है।
{
"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
}
}ये वे नाम हैं जिन्हें आप वास्तव में आयात करेंगे। प्रत्येक को दस्तावेज़ीकरण साइट से कॉपी करने के बजाय 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 में अनुक्रमणिका करें: गेटर का रिटर्न प्रकार एक ही वर्ग है, और उपनाम सभी संस्करणों में स्थिर है।
BlockManagerEditor['Blocks']StorageManagerEditor['Storage']ComponentManagerEditor['Components']grapesjs.init() एक Editor लौटाता है। चर को एनोटेट करना वैकल्पिक है - अनुमान पहले से ही इसे सही हो जाता है - लेकिन प्रकार का नामकरण वह है जो आपको संपादक को मॉड्यूल सीमाओं के पार बिना किसी भी चौड़ा किए बिना पास करने देता है।
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();एक ढांचे में संपादक पहले रेंडर के लिए मौजूद नहीं है, और अनमाउंट के बाद मौजूद नहीं होना चाहिए। धारक को Editor | null के रूप में टाइप करने से कंपाइलर प्रत्येक कॉल साइट पर दोनों क्षणों के बारे में पूछता है। इसे Editor के रूप में टाइप करना और इसे दूर करने से उस प्रश्न को उत्पादन में ले जाया जाता है।
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 के माध्यम से उपनाम करें।
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;
}editor.on ईवेंट के नाम पर सामान्य है, इसलिए कॉलबैक हस्ताक्षर आपके द्वारा पास की गई स्ट्रिंग से लिया गया है। व्यवहार में इसका मतलब है कि आपको लगभग कुछ भी एनोटेट नहीं करना चाहिए - अनुमान आपको सही पैरामीटर प्रकार देता है, और एक एनोटेशन जो असहमत है वह एक मूक बेमेल के बजाय एक संकलन त्रुटि है।
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');
});
}ईवेंट का नाम एक ओपन स्ट्रिंग यूनियन है, जानबूझकर: प्लगइन्स अपने स्वयं के चैनलों को परिभाषित करते हैं और उन्हें संकलित करते रहना चाहिए। लागत यह है कि एक मुख्य ईवेंट नाम में एक टाइपो अभी भी मान्य है TypeScript - कॉलबैक बस एक ढीले हस्ताक्षर पर वापस आ जाता है और कभी भी आग नहीं लगता। जब कोई ईवेंट हैंडलर रहस्यमय तरीके से कुछ नहीं करता है, तो API की जांच करने से पहले वर्तनी की जांच करें।
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) => { ... });
}एक घटक प्रकार कैनवास में नए व्यवहार को पंजीकृत करता है: एक टैग, इसका traits, यह बच्चों के रूप में क्या स्वीकार करता है, जब HTML को वापस पार्स किया जाता है तो इसे कैसे पहचाना जाता है। यह वह जगह है जहां अधिकांश कस्टम संपादक का काम होता है, और जहां GrapesJS के प्रकार और आपके बीच की सीमा खींची जानी होती है।
editor.Components.addType(प्रकार, विकल्प) AddComponentTypeOptions लेता है — मॉडल, दृश्य, isComponent, विस्तार — ComponentDefinition नहीं। ComponentDefinition एक पेड़ के अंदर एक घोषित नोड का वर्णन करता है: एक घटक के बच्चे, या एक ब्लॉक की सामग्री। ट्यूटोरियल जो ComponentDefinition को addType में पास करते हैं, वे एक पुराने आकार को उद्धृत कर रहे हैं, और इससे आपको जो त्रुटि मिलती है वह स्पष्ट नहीं है।
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,
};
}GrapesJS प्रकार संपादक का वर्णन करते हैं API। आपके अपने इंटरफेस को आपके उत्पाद के मॉडल का वर्णन करना चाहिए। उन्हें मिलाना लगभग एक सप्ताह तक कुशल लगता है: फिर आपके डेटाबेस को जिस फ़ील्ड की आवश्यकता होती है, उसमें एक घटक विशेषता को छोड़कर रहने के लिए कहीं नहीं होता है, और एक घटक के आंतरिक भाग आपके स्कीमा का हिस्सा बन जाते हैं। ऊपर readHero जैसे फ़ंक्शन को एकमात्र स्थान के रूप में रखें जहां दोनों मिलते हैं - डाउनस्ट्रीम में सब कुछ आपके इंटरफ़ेस को लेता है, न कि Component।
एक ब्लॉक वह है जो बाएं हाथ के शेल्फ में दिखाई देता है और उपयोगकर्ता क्या खींचता है। यह एक घटक नहीं है - यह एक घोषणा है कि क्या सम्मिलित करना है। दोनों को सीधा रखना जल्दी करने लायक है, क्योंकि उनके प्रकार विनिमेय नहीं हैं और त्रुटि संदेश ऐसा नहीं कहता है।
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 बनाया गया Block लौटाता है, ताकि आप इसे कैप्चर कर सकें और बाद में शेल्फ को समायोजित कर सकें - उपयोगकर्ता की योजना में शामिल नहीं होने वाले ब्लॉक को फिर से व्यवस्थित करना, छिपाना या रनटाइम पर श्रेणी लेबल की अदला-बदली करना।
अगले: यह सब एक प्लगइन के रूप में पैकेज करेंएक 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.mdimport 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;क्लोजर पास करने से आपके विकल्प कॉल साइट पर टाइप किए जाते हैं। विकल्प - प्लगइन्स में प्लगइन और इसकी सेटिंग्स को pluginsOpts में सूचीबद्ध करना - उन सेटिंग्स को एक ढीले रिकॉर्ड के रूप में टाइप करता है, इसलिए एक गलत वर्तनी वाली कुंजी संकलित होती है और चुपचाप कुछ भी नहीं करती है।
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)],
});एक डिज़ाइन-सिस्टम अनुभाग एक घटक नहीं है - यह एक छोटा पेड़ है जिस आकार के लिए आपके उत्पाद का पहले से ही एक नाम है। उस आकार का एक बार वर्णन करना, एक इंटरफ़ेस के रूप में, संपादक, API और रेंडरर को अलग होने से रोकता है।
Hero ← one component type, one interface
├── Heading ← extends 'text'
├── Description ← extends 'text'
└── Button ← extends 'link', traits: label + hrefimport 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' },
],
},
},
});
}अदायगी आज कम बग नहीं है - यह है कि छह महीने बाद, HeroContent में एक फ़ील्ड जोड़ने से स्ट्रिंग 'हेडलाइन' के लिए कोडबेस पर खोज के बजाय हर उस स्थान की एक सूची तैयार होती है जिसे बदलना पड़ता है।
अगला: इसे अपने डेटाबेस के अंदर और बाहर निकालेंभंडारण वह जगह है जहां दो प्रकार के सिस्टम सबसे परिणामी तरीके से मिलते हैं, क्योंकि यह वह सीमा है जो आपके डेटाबेस में समाप्त होती है। इसे गलत करना बाद में महंगा है; इसे सही करना लगभग बीस लाइनें हैं।
ProjectData संपादक का अपना JSON है। इसकी आंतरिक संरचना GrapesJS से संबंधित है, संस्करणों के बीच परिवर्तन करती है, और हाथ से माइग्रेट करने के लिए कुछ नहीं है। आपका ProjectRecord एक पंक्ति है: एक आईडी, एक मालिक, एक नाम, एक संस्करण, टाइमस्टैम्प - साथ ही एक कॉलम में वह अपारदर्शी बूँद। इसे स्टोर करें, इसे लोड करें और इसके अंदरूनी हिस्से को अकेला छोड़ दें।
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;
}संपादक प्रोजेक्ट डेटा तैयार करता है। आपका स्टोरेज एडाप्टर एकमात्र कोड है जो दोनों पक्षों को छूता है।
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;
}एक आधिकारिक React आवरण है @grapesjs/react, MIT-लाइसेंस प्राप्त, वर्तमान में 2.0.0 - और यह अपनी स्वयं की घोषणा फ़ाइल भेजता है। यह कैनवास के अंदर React घटकों को प्रस्तुत नहीं करता है; यह संपादक को माउंट करता है और आपको उदाहरण देता है।
'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 लगभग पंद्रह पंक्तियों में एक ही काम करता है, और यदि आप रैपर का उपयोग करते हैं तो भी यह समझने योग्य है, क्योंकि यह दो नियमों को स्पष्ट करता है: रेफरी की रक्षा करें, और सफाई पर नष्ट करें।
'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} />;
}संपूर्ण Next.js प्रश्न एक सीमा है। grapesjs.init को एक वास्तविक DOM तत्व, साथ ही दस्तावेज़ और विंडो की आवश्यकता होती है; एक Server Component में उनमें से कोई भी नहीं है। तो संपादक Client Component में जाता है, और इसके ऊपर की हर चीज़ सर्वर पर रह सकती है।
'use client' संपादक बनाने वाले घटक के शीर्ष पर है, और कहीं भी अधिक नहीं है। इसके ऊपर का पृष्ठ Server Component रहता है: यह पैरा की प्रतीक्षा करता है, सत्र की जांच करता है, प्रोजेक्ट को लोड करता है और सादे प्रॉप्स को पास करता है। यह विभाजन सुरक्षित रखने लायक है, क्योंकि एक फ़ाइल को ऊपर ले जाने से 'use client' चुपचाप आपका डेटा लोड हो रहा है क्लाइंट कोड में बदल जाता है।
// 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} />;
}// 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} />;
}दोनों काम करते हैं, और दोनों मैनुअल React संस्करण के समान आकार का पालन करते हैं: एक टेम्पलेट रेफरी, तत्व मौजूद होने के बाद आरंभीकरण, टियरडाउन पर नष्ट हो जाता है। ढांचा-विशिष्ट यांत्रिकी के पास यहां एक संघनित संस्करण के बजाय अपने स्वयं के गाइड हैं।
एक टेम्पलेट रेफरी प्लस onMounted/onBeforeUnmount, जिसमें संपादक प्रतिक्रियाशील स्थिति के बाहर रखा जाता है - Editor को ref() में लपेटने से Vue प्रॉक्सी एक ऐसी वस्तु बन जाती है जो अपने स्वयं के आंतरिक का प्रबंधन करती है। कोई आधिकारिक Vue आवरण नहीं है।
GrapesJS + Vue गाइड@ViewChild कंटेनर के लिए, ngAfterViewInit शुरू करने के लिए, ngOnDestroy को फाड़ने के लिए - और runOutsideAngular ताकि संपादक का अपना ईवेंट लूप परिवर्तन का पता लगाने को प्रेरित न करे। कोई आधिकारिक Angular आवरण नहीं है।
GrapesJS + Angular गाइडदोनों ही मामलों में प्रकार वही हैं जिनका उपयोग यह पृष्ठ कर रहा है: Editor, Component, ProjectData। फ्रेमवर्क बदल जाता है जहां init() कहा जाता है, न कि जो यह लौटाता है वह नहीं।
ऊपर दी गई हर चीज़ एक फ़ाइल में फिट बैठती है। यह लगभग तीसरे कस्टम घटक पर फिट होना बंद कर देता है, और जो चीज यह तय करती है कि अगला वर्ष सुखद है या नहीं, वह वह है जहां आप अपने एप्लिकेशन और संपादक के बीच सीम डालते हैं।
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 - और दुर्घटना से भी संपादक आंतरिक तक नहीं पहुंच सकता है।
// 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;
}शीर्ष पर आपका आवेदन, बीच में आपके प्रकार, नीचे संपादक। निर्भरताएं नीचे की ओर इशारा करती हैं और कभी भी वापस नहीं आती हैं।
तुम्हारा। GrapesJS के बारे में कुछ नहीं जानता।
सीवन। एकमात्र स्थान दोनों दुनिया का नाम रखा गया है।
तुम्हारा। एकमात्र कोड जो संपादक से आयात करता है।
संपादक। पैकेज द्वारा टाइप किया गया।
एक पेज-बिल्डर उत्पाद ज्यादातर पेज बिल्डर नहीं होता है। GrapesJS इस श्रृंखला में एक बॉक्स को कवर करता है; बाकी एक एप्लिकेशन है जिसे आप वैसे भी लिखने जा रहे थे, और उनके बीच जुड़ाव टाइप करना ही यह मार्गदर्शिका का निर्माण कर रही है।
GrapesJS संपादन सतह का मालिक है। प्रमाणीकरण, भंडारण, किरायेदारी, बिलिंग और प्रकाशन आपका है।
GrapesJS संपादन सतह का मालिक है। प्रमाणीकरण, भंडारण, किरायेदारी, बिलिंग और प्रकाशन आपका है।
हर उस चीज के बारे में संपादक की कोई राय नहीं है।
कैनवास के अंदर सब कुछ, पैकेज द्वारा टाइप किया गया।
संपादक आपके उत्पाद का एक घटक है, इसका विकल्प नहीं।
ग्यारह विफलताएं जो बार-बार सामने आती हैं, उनमें से अधिकांश सामान्य रूप से TypeScript के बजाय इस जोड़ी के लिए विशिष्ट हैं। हर एक लक्षण है जिसके साथ आप मेल खा सकते हैं और वह परिवर्तन जो इसे ठीक करता है।
लक्षण
npm install fails E404 के साथ, या एक ट्यूटोरियल आपको इसे जोड़ने के लिए कहता है और आप मान लेते हैं कि आपकी रजिस्ट्री टूट गई है।
ठीक करना
इसे हटा दें। प्रकार grapesjs के अंदर ही हैं, पैकेज के प्रकार फ़ील्ड द्वारा संदर्भित। कोई अलग प्रकार का पैकेज नहीं है और वर्तमान लाइन के लिए एक भी नहीं है।
लक्षण
संपादक को दें: कोई भी, आमतौर पर सेटअप के दौरान एक त्रुटि को शांत करने के लिए जोड़ा जाता है, और कभी नहीं हटाया जाता है।
ठीक करना
Editor 'grapesjs' से। जड़ में एक भी हर प्रबंधक, हर ईवेंट पेलोड और हर निर्यात कॉल के लिए फैलता है - आप TypeScript की संकलन-समय लागत रखते हैं और सभी लाभ खो देते हैं।
लक्षण
एक प्लगइन विकल्प लेता है: कोई भी या रिकॉर्ड<string, unknown>; उपभोक्ताओं का अनुमान है कि फ़ील्ड नाम और टाइपो कुछ नहीं करते हैं।
ठीक करना
एक विकल्प इंटरफ़ेस घोषित करें और निर्यात करें, फिर फ़ंक्शन को Plugin<YourOptions> के रूप में टाइप करें। फिर कॉल साइट सहित दोनों मापदंडों की जाँच की जाती है।
लक्षण
एक Block पास करना जहां एक Component की उम्मीद है, या एक ब्लॉक को स्टाइल करने की कोशिश करना और इसे ढूंढना कोई शैली नहीं है।
ठीक करना
एक ब्लॉक एक शेल्फ प्रविष्टि है जो बताती है कि क्या डालना है। एक घटक कैनवास में एक नोड है। Blocks.add BlockProperties लेता है; Components.addType AddComponentTypeOptions लेता है।
लक्षण
एक घटक प्रकार पंजीकृत होता है लेकिन एक सादे 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 समस्या नहीं है। वे ऐसे स्थान हैं जहां संपादक का मॉडल और आपके उत्पाद का मॉडल एक-दूसरे के लिए भ्रमित हो जाते हैं, और टाइप सिस्टम केवल वही है जो भ्रम को जल्दी दिखाई देता है।
चार त्रुटि आकृतियाँ लगभग सब कुछ कवर करती हैं। प्रत्येक मामले में उपयोगी कदम किसी भी तक पहुंचने के बजाय घोषणा फ़ाइल को node_modules में देखना है - उत्तर वहां है, और कोई भी केवल प्रश्न को स्थगित कर देता है।
आप देख सकते हैं
आयात लाइन पर TS2307, भले ही पैकेज स्पष्ट रूप से स्थापित हो और संपादक रनटाइम पर ठीक चलता हो।
जाँच
आपका TypeScript संस्करण पहले। 5.0 से नीचे घोषणा फ़ाइल को पार्स नहीं किया जा सकता है और विफलता को एक लापता मॉड्यूल के रूप में रिपोर्ट किया जाता है - वास्तव में भ्रामक संदेश। फिर moduleResolution: यह bundler, node16 या nodenext होना चाहिए, क्लासिक नहीं। @types/grapesjs जोड़ने से मदद नहीं मिलेगी; वह पैकेज मौजूद नहीं है।
आप देख सकते हैं
TS2614 एक नाम पर जिसे आप घोषणा फ़ाइल में देख सकते हैं, अक्सर StorageManager या BlockManager।
जाँच
प्रबंधक कक्षाएं घोषित की जाती हैं लेकिन निर्यात नहीं की जाती हैं। अनुक्रमित-एक्सेस उपनाम का उपयोग करें - Editor['Storage'], Editor['Blocks'], Editor['Components'] - जो एक ही वर्ग में हल हो जाता है। यदि नाम कुछ और है, तो grep node_modules/grapesjs/dist/index.d.ts: यदि यह नहीं है, तो यह पुराने संस्करण से संबंधित है।
आप देख सकते हैं
एक ईवेंट हैंडलर, एक addType कॉल, या एक ब्लॉक घोषणा जो एक ट्यूटोरियल से सटीक रूप से मेल खाती है और अभी भी संकलित नहीं होगी।
जाँच
हस्ताक्षर, घोषणा फ़ाइल में। ईवेंट प्रति नाम अलग-अलग पेलोड ले जाते हैं; addType ComponentDefinition के बजाय AddComponentTypeOptions लेता है। अपने संपादक में विधि को होवर करें - वास्तविक हस्ताक्षर वहीं है, और यह आमतौर पर आपके द्वारा कॉपी किए गए लेख से अलग आकार का होता है।
आप देख सकते हैं
एक React या Next.js बिल्ड जहां रैपर के Editor और आपका एकजुट होने से इनकार करते हैं, और संदेश दो node_modules पथों को नाम देता है।
जाँच
डुप्लिकेट इंस्टॉल करता है। npm ls grapesjs दूसरी प्रति दिखाएगा, जिसे आमतौर पर एक संकीर्ण सहकर्मी सीमा के साथ एक प्लगइन द्वारा खींचा जाता है। संस्करणों को डुप्लिकेट या संरेखित करें; रैपर की अपनी सहकर्मी सीमा ^0.22.5 है।
फ्रेमवर्क-विशिष्ट प्रकार की त्रुटियों के लिए, React और Next.js मार्गदर्शिकाएँ इस पृष्ठ की तुलना में अधिक गहराई तक जाती हैं।
सटीक संस्करण, रजिस्ट्री के खिलाफ और स्थापित घोषणा फ़ाइल के खिलाफ जाँच की गई। विशेष रूप से TypeScript फर्श को प्रत्येक रिलीज के खिलाफ संकलित करके मापा गया था, जो कि चेंजलॉग से अनुमान नहीं लगाया गया था।
| पैकेज | सत्यापित किया गया | इसका क्या मतलब है |
|---|---|---|
grapesjs | 0.23.6 | अपने स्वयं के प्रकार dist/index.d.ts पर भेजता है। कोई अलग प्रकार का पैकेज मौजूद नहीं है। |
typescript | >= 5.0 | मंजिल। 4.9 और नीचे घोषणा फ़ाइल को पार्स नहीं कर सकते हैं, और इसे लापता मॉड्यूल के रूप में रिपोर्ट नहीं कर सकते हैं। |
typescript | 7.0.2 | वर्तमान रिलीज़, और इस गाइड के नमूने जिस संस्करण के साथ संकलित किए गए थे। 5.0 से सब कुछ काम करता है। |
@grapesjs/react | 2.0.0 | आधिकारिक React रैपर, MIT-लाइसेंस प्राप्त, अपने स्वयं के बंडल प्रकारों के साथ। |
react | ^18.0.0 || ^19.0.0 | रैपर की React पीयर रेंज। React 17 पर, संपादक को useEffect के साथ मैन्युअल रूप से प्रारंभ करें। |
grapesjs (peer) | ^0.22.5 | रैपर की grapesjs पीयर रेंज - इतनी चौड़ी कि वर्तमान कोर इसे संतुष्ट करता है। |
node | >=20.9.0 | GrapesJS एक ब्राउज़र लाइब्रेरी है और घोषित करता है कि कोई इंजन फ़ील्ड नहीं है। आप वास्तव में जिस मंजिल से टकराते हैं वह आपके ढांचे से आता है; Next.js 16.3.4 इसकी आवश्यकता है। |
registry.npmjs.org और node_modules/अंगूर/dist/index.d.ts के खिलाफ सत्यापित 2026-09-03। इस पृष्ठ पर प्रत्येक कोड नमूना प्रकाशन से पहले सख्त मोड के तहत इन संस्करणों के खिलाफ संकलित किया गया था।
यहां कोई "प्रत्येक TypeScript संस्करण के साथ काम करता है" नहीं है, क्योंकि यह सच नहीं है: 5.0 एक कठोर मंजिल है और इसके नीचे विफलता मोड इतना भ्रमित करने वाला है कि यह सटीक रूप से बताने लायक है।
एक बार जब आप कोर API को समझ लेते हैं, तो प्लगइन्स आपको हर सुविधा को खरोंच से बनाने की आवश्यकता के बिना अतिरिक्त कार्यक्षमता प्रदान कर सकते हैं। ये GJS.Market पर वर्तमान लिस्टिंग हैं, जिन्हें टाइप की गई सतह के किस हिस्से को छूता है, इसके आधार पर समूहीकृत किया जाता है।
जहां ProjectData आपके डेटाबेस से मिलता है। इस गाइड का भंडारण अनुभाग किस परत के बारे में है।
श्रेणी ब्राउज़ करेंहेडलेस CMS बैकएंड के लिए एक स्टोरेज एडाप्टर - वही लोड/स्टोर अनुबंध जिसे आप हाथ से लागू करेंगे।
ब्राउज़र-स्थानीय दृढ़ता। रिमोट एडाप्टर के सामने एक ड्राफ्ट परत के रूप में उपयोगी।
Firestore प्रोजेक्ट स्टोर के रूप में, दस्तावेज़ आपके ProjectRecord के लिए खड़ा है।
परियोजनाओं के लिए Firebase-समर्थित भंडारण, Storage Manager के माध्यम से वायर्ड।
Component प्रकार आप अन्यथा addType के साथ खुद को पंजीकृत करेंगे।
श्रेणी ब्राउज़ करेंएक टैब्ड घटक प्रकार, अपने स्वयं के traits के साथ — addType का एक कार्यशील उदाहरण जिसे आप पढ़ सकते हैं.
एक पिकर विशेषता के साथ एक आइकन घटक, यह दर्शाता है कि एक विशेषता एक घटक क्षेत्र को कैसे चलाती है।
पुनः प्रयोज्य लिंक किए गए उदाहरणों को फिर से प्रयोज्य किया जाता है, इसलिए एक संपादन पृष्ठों पर फैलता है।
एक टाइपराइटर-प्रभाव घटक रैपिंग Typed.js — एक तृतीय-पक्ष पुस्तकालय जो एक घटक प्रकार के रूप में उजागर होता है।
किसी घटक के HTML और CSS को संपादित करें, जो यह देखने का सबसे तेज़ तरीका है कि आपके घटक प्रकार वास्तव में क्या उत्पादन करते हैं।
संपादक के अंदर से घटक स्क्रिप्ट संलग्न करें और संपादित करें।
संपादक उपयोगिताओं का एक सेट जिसका उद्देश्य अंतिम उपयोगकर्ताओं के बजाय GrapesJS पर निर्माण करने वाले लोगों के उद्देश्य से है।
संपादक में मल्टी-प्रोजेक्ट हैंडलिंग, ऊपर की भंडारण परत के निकट।
React-आधारित संपादक UI GrapesJS कैनवास के आसपास।
एक काम किया गया React एकीकरण जिसे आप इस गाइड के React अनुभाग के साथ पढ़ सकते हैं।
hero-आधारित स्टैक के लिए एक React घटक - वह अनुभाग जो यह मार्गदर्शिका हाथ से बनाती है।
React डेवलपर्स, बंडलिंग ब्लॉक और घटकों के उद्देश्य से एक प्रीसेट।
एक बात यह पृष्ठ आपको नहीं बताएगा: इनमें से कोई भी लिस्टिंग बंडल TypeScript घोषणाओं का विज्ञापन नहीं करती है, इसलिए प्रकार के समर्थन को असत्यापित मानें और प्लगइन के स्वयं के README की जांच करें। इस बात की परवाह किए बिना कि प्लगइन को प्राप्त होने वाला संपादक कोर पैकेज द्वारा टाइप किया जाता है - इसलिए किसी भी प्लगइन के आसपास आपके एकीकरण कोड की जाँच की जाती है, तब भी जब प्लगइन स्वयं सादा जावास्क्रिप्ट हो।
लाइन कठिनाई के बारे में नहीं है। यह इस बारे में है कि क्या व्यवहार आपके उत्पाद के लिए विशिष्ट है - क्योंकि यही तय करता है कि इसे दो साल में किसे बनाए रखना है।
| माँग | अपने आप को बनाएं | प्लगइन का उपयोग करें |
|---|---|---|
| आपके व्यवसाय के लिए विशिष्ट व्यवहार | हाँ - कोई और इसे नहीं बनाएगा | — |
| सामान्य संपादक कार्यक्षमता | — | हाँ - पहले ही हल हो चुका है |
| कोड का पूर्ण नियंत्रण | हाँ | हां, ओपन-सोर्स प्लगइन्स के लिए |
| पहले काम करने वाले संस्करण का प्रयास | उच्चतर | निचला प्रारंभिक बिंदु |
| इसका रखरखाव कौन करता है | आपकी टीम | Plugin लेखक, साथ ही आपका एकीकरण |
| आप इसे कितनी दूर तक बदल सकते हैं | जहां तक आप चाहें | प्लगइन पर निर्भर करता है |
व्यवहार में अधिकांश संपादक दोनों हैं: प्रत्येक संपादक को आवश्यक भागों के लिए मुट्ठी भर प्लगइन्स, और उन भागों के लिए आपके स्वयं के टाइप किए गए घटक प्रकार जो उत्पाद को आपका बनाते हैं।
इस पृष्ठ पर प्रकार हर जगह समान हैं। क्या परिवर्तन होता है जहां आप init() कहते हैं और आप कैसे सफाई करते हैं।
कोई ढांचा, या एक ढांचा नहीं है जिसे यह सूची नाम नहीं देती है। उपरोक्त सब कुछ सीधे लागू होता है।
गाइड खोलेंआधिकारिक आवरण, रेफरी, सफाई और StrictMode।
गाइड खोलेंक्लाइंट सीमा, सर्वर डेटा लोड हो रहा है, App Router।
गाइड खोलेंटेम्पलेट रेफरी, onMounted, और संपादक को प्रतिक्रियाशील स्थिति से बाहर रखता है।
गाइड खोलेंViewChild, जीवनचक्र हुक और परिवर्तन का पता लगाना।
गाइड खोलेंGrapesJS ट्यूटोरियल से शुरू करें, फिर प्रकारों के लिए वापस आएं।
गाइड खोलेंआगे कहां जाना है, यह इस बात पर निर्भर करता है कि आप अभी भी संपादक सीख रहे हैं, इसे एक ढांचे में जोड़ रहे हैं, या इसके चारों ओर एक उत्पाद बना रहे हैं।
यदि आर्किटेक्चर अनुभाग वह है जहां आपका प्रोजेक्ट वास्तव में है, तो शेष कार्य आमतौर पर संपादक सुविधाओं के बजाय एकीकरण होता है। हम यही करते हैं।
टाइप किए गए GrapesJS API से शुरुआत करें, अपने स्वयं के घटक और प्लगइन्स बनाएं, अपने एप्लिकेशन इंफ्रास्ट्रक्चर को कनेक्ट करें, और जब आपके उत्पाद को अधिक कार्यक्षमता की आवश्यकता हो तो संपादक का विस्तार करें।
पैकेज स्थापित करें, संपादक टाइप करें और कुछ ही मिनटों में एक कार्यशील टाइप किया हुआ सेटअप प्राप्त करें।
ट्यूटोरियल शुरू करेंस्टोरेज एडेप्टर, घटक प्रकार और डेवलपर टूलींग पहले से ही GrapesJS के लिए बनाया गया है।
प्लगइन्स का अन्वेषण करेंटाइप किए गए प्लगइन्स, फ्रेमवर्क एकीकरण और उत्पादन वास्तुकला, आपके साथ बनाया गया।
कस्टम विकास प्राप्त करेंTypeScript GrapesJS को सुरक्षित नहीं बनाता है। एक फ़ाइल से आगे निकलने के बाद यह एक अनुकूलित GrapesJS संपादक को बनाए रखने योग्य बनाता है।