From 181da62b8ca847b02b593d40d668162a5931a906 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 17 Mar 2022 15:13:11 +0100 Subject: [PATCH] Update storageManager doc --- docs/modules/Storage.md | 125 ++++++++++++++++++++++----- package.json | 3 +- src/storage_manager/config/config.js | 7 +- yarn.lock | 2 +- 4 files changed, 111 insertions(+), 26 deletions(-) diff --git a/docs/modules/Storage.md b/docs/modules/Storage.md index 0fc5fe0fa..e7fc0ee44 100644 --- a/docs/modules/Storage.md +++ b/docs/modules/Storage.md @@ -4,64 +4,144 @@ title: Storage Manager # Storage Manager -The aim of this guide is to show how to setup correctly your storage configuration for common usages of the editor and explain also some additional advanced settings +The Storage Manager is a built-in module that allows the persistence of your project data. The aim of this guide is to show how to setup correctly your storage configuration for common usages of the editor and explain also some additional advanced settings. ::: warning -This guide requires GrapesJS v0.14.15 or higher +This guide requires GrapesJS v0.19.* or higher ::: [[toc]] -## Basic configuration +## Configuration + +To change the default configurations you have to pass the `storageManager` property with the main configuration object. -The storage manager is a built-in module implemented inside GrapesJS which allows the persistence of your data. By default, GrapesJS saves the data locally by using the built-in `LocalStorage` which just leverages [localStorage API]. -You can initialize the editor with different storage configurations via `storageManager` option: ```js const editor = grapesjs.init({ ... // Default configurations storageManager: { - id: 'gjs-', // Prefix identifier that will be used on parameters - type: 'local', // Type of the storage - autosave: true, // Store data automatically - autoload: true, // Autoload stored data on init - stepsBeforeSave: 1, // If autosave enabled, indicates how many changes are necessary before store method is triggered + type: 'local', // Storage type. Available: local | remote + autosave: true, // Store data automatically + autoload: true, // Autoload stored data on init + stepsBeforeSave: 1, // If autosave is enabled, indicates how many changes are necessary before the store method is triggered + // ... + // Default storage options + options: { + local: {/* ... */}, + remote: {/* ... */}, + } }, }); ``` -The `id` option is used to prevent collisions (quite common with localStorage) in case of multiple editors on the same page, therefore you will see parameters passed like `{ 'gjs-components': '...', 'gjs-styles': '...', }` -If you need to disable the storage manager you can pass any empty `type`: +In case you don't need any persistence, you can disable the module in this way: ```js -... -storageManager: { type: null }, +const editor = grapesjs.init({ + ... + storageManager: false, +}); ``` -For all other available options check directly the [configuration source file](https://github.com/artf/grapesjs/blob/dev/src/storage_manager/config/config.js). +Check the full list of available options here: [Storage Manager Config](https://github.com/artf/grapesjs/blob/master/src/storage_manager/config/config.js) + + + + + +## Project data + +The project data is a JSON object containing all the necessary information (styles, pages, etc.) about your project in the editor. You can get the current state of the data in this way: + +```js +const projectData = editor.getProjectData(); +``` + +That object is used in the storage manager methods in order to store and load your project data (locally or remotely in your DB/file). + +::: danger +You should only rely on the JSON project data in order to load your project properly in the editor. + +The editor is able to parse and use HTML/CSS code, you can use it as part of your project initialization but never rely on it as a persitance layer in the load of projects as many information could be stripped off. +::: + + + + +## Setup local storage + +By default, GrapesJS saves the data locally by using the built-in `local` storage which leverages [localStorage API]. + +The only option you might probably care for the local storage is the `key` used to store the data. If the user loads different projects in your application, you might probably need to differentiate the local storage by the ID of the project (the ID here is intended to be part of your application domain). + +```js +// Get your project ID (eg. taken from the route) +const projectId = getProjectId(); + +const editor = grapesjs.init({ + ... + storageManager: { + type: 'local', + options: { + local: { key: `gjsProject-${projectId}` } + } + }, +}); +``` ## Setup remote storage -Switching up the remote storage is very simple, it's just a matter of specifying your endpoints for storing and loading, which generally might be also the same (if you rely on HTTP methods). +Most commonly the data of the project might be saved remotely on your server (DB, file, etc.) therefore you need to setup your server-side API calls in order to store/load project data. + +For the sake of simplicity we can setup a fake REST API server by relying on [json-server]. + +```sh +mkdir my-server +cd my-server +npm init +npm i json-server +echo '{"projects": [ {"id": 1, "data": {"assets": [], "styles": [], "pages": [{"component": "
Initial content
"}]} } ]}' > db.json +npx json-server --watch db.json +``` + +This will start up a local server with one single project available on `http://localhost:3000/projects/1`. The data will be updated on the `db.json` file. + +Here below an example of how you would configure a `remote` storage in GrapesJS. ```js +const projectID = 1; +const projectEndpoint = `http://localhost:3000/projects/${projectID}`; + const editor = grapesjs.init({ ... storageManager: { type: 'remote', stepsBeforeSave: 3, - urlStore: 'http://endpoint/store-template/some-id-123', - urlLoad: 'http://endpoint/load-template/some-id-123', - // For custom parameters/headers on requests - params: { _some_token: '....' }, - headers: { Authorization: 'Basic ...' }, + options: { + remote: { + urlLoad: projectEndpoint, + urlStore: projectEndpoint, + // The `remote` storage uses the POST method when stores data but + // the json-server API requires PATCH. + fetchOptions: opts => (opts.method === 'POST' ? { method: 'PATCH' } : {}), + // As the API stores projects in this format `{id: 1, data: projectData }`, + // we have to properly update the body before the store and extract the + // project data from the response result. + onStore: data => ({ id: projectID, data }), + onLoad: result => result.data, + } + } } }); ``` -As you can see we've left some default option unchanged, increased changes necessary for autosave triggering and passed remote endpoints. + +::: danger +Be sure to configure properly [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) on your server API. The [json-server] is not intended to be used in production and therefore enables all of them automatically for the sake of simplicity. +::: @@ -298,3 +378,4 @@ editor.on('storage:end:load', (resultObject) => { [grapesjs-firestore]: [localStorage API]: [IndexedDB]: +[json-server]: diff --git a/package.json b/package.json index 06b3280d3..3299b9ead 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "grapesjs", "description": "Free and Open Source Web Builder Framework", - "version": "0.18.3", + "version": "0.19.0", "author": "Artur Arseniev", "license": "BSD-3-Clause", "homepage": "http://grapesjs.com", @@ -29,6 +29,7 @@ "documentation": "^13.2.5", "eslint": "^7.32.0", "grapesjs-cli": "^3.0.0", + "html-entities": "^1.4.0", "husky": "^2.7.0", "jest": "^24.9.0", "lint-staged": "^8.2.1", diff --git a/src/storage_manager/config/config.js b/src/storage_manager/config/config.js index e070b5f50..65fb46b51 100644 --- a/src/storage_manager/config/config.js +++ b/src/storage_manager/config/config.js @@ -66,12 +66,15 @@ export default { credentials: 'include', /** - * Edit project data before sending them to the storage. + * The remote storage sends the project data as a body of the request. + * You can use this method to update the body before the store call in order to align + * with your API requirements. */ onStore: data => data, /** - * Edit project data before loading them from the storage. + * The remote storage loads the project data directly from the request response. + * You can use this method to properly extract the project data from the response. */ onLoad: result => result, }, diff --git a/yarn.lock b/yarn.lock index c7ddc2351..aabc2749b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6352,7 +6352,7 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" -html-entities@^1.3.1: +html-entities@^1.3.1, html-entities@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"