Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow plugins to be defined as functions #1301

Merged
merged 2 commits into from
Aug 8, 2018
Merged

Allow plugins to be defined as functions #1301

merged 2 commits into from
Aug 8, 2018

Conversation

loganvolkers
Copy link
Contributor

As a developer that is using a lot of custom GrapesJS plugins, I would like to import plugins and use them directly without having to define them in the global plugin registry.

This allows my code to be more modular without having to worry about another plugin using the same string namespace that my plugin is trying to use.

Benefits:

  • Avoids the possibility of namespace conflicts
  • Lowers the bar for people to develop their first plugin
  • Allows for vanilla javascript plugin composition and higher order plugins
  • Plugins don't need to import and/or bundle Grapes e.g. nicer boilerplate

Using imports

  import grapesPluginFn from "./awesomePlugin";

  const editor = grapesjs.init({
      container : '#gjs',
      plugins: ['my-plugin-name', grapesPluginFn ]
  });

Using local plugins

  function customizeMyEditor(editor,options){
     editor.BlockManager.add('test-block', {
        ...
     });
  }

  const editor = grapesjs.init({
      container : '#gjs',
      plugins: ['my-plugin-name', customizeMyEditor]
  });

Lambda plugins

  const editor = grapesjs.init({
      container : '#gjs',
      plugins: ['my-plugin-name', (editor) => console.log("Pimping the editor before it renders", editor)]
  });

src/index.js Show resolved Hide resolved
@artf
Copy link
Member

artf commented Jul 26, 2018

Hi Logan, I like this concept, those benefits are real and it doesn't break current API, so I don't see any reason of why to not apply it.
Would you mind to add a test case here and add few lines about this approach here? It'd be great

@loganvolkers
Copy link
Contributor Author

Thanks for the feedback, I'll see about adding some tests and docs soon.

@loganvolkers
Copy link
Contributor Author

FYI - I might have gone too far with the docs. I think that this new functional approach to plugins is much nicer that the old namespace approach, and I'd like to see all plugins migrated this way.

That is in part because in our project we have problems with this:

export default grapesjs.plugins.add('my-plugin-name', (editor, options) => {
  console.log(options);
  //{ customField: 'customValue' }
})

Because we use a bundler and lots of tests, it's a pain to always force grapesjs into global scope, causing workaround like this:

import grapesjs from 'grapesjs'
windows.grapesjs  = grapesjs

function onLoad(){
   require("grapesjs-preset-newsletter");
}

That sounds like a bigger project, but I figured it would be a good idea to share.

@loganvolkers
Copy link
Contributor Author

@artf Can you have a look at this CI error? Tests are working locally.

    SecurityError: localStorage is not available for opaque origins

^ that's the error that I'm getting, and it sounds unrelated to the feature I added

@artf
Copy link
Member

artf commented Aug 8, 2018

Thanks Logan, about your issue with other plugins I think that happens because of the previous boilerplate when I wasn't using the import grapesjs ... (old index, new index)

BTW, I'm gonna merge this PR because I like the approach and it doesn't cost too much, but still not sure about using it as a recommended way, especially when you use plugins directly in the browser

<script src="/your/path/to/grapesjs.min.js"></script>
<script src="/your/path/to/grapesjs-plugin.js"></script>
...
grapesjs.init({
	container : '#gjs',
    plugins: [ ?? ] // would require some kind of global
})

Can you have a look at this CI error? Tests are working locally.

Seems to be related here, I think with a new version of jest will be fixed

@artf artf merged commit c9153dd into GrapesJS:dev Aug 8, 2018
@loganvolkers
Copy link
Contributor Author

... still not sure about using it as a recommended way, especially when you use plugins directly in the browser
plugins: [ ?? ] // would require some kind of global

To be clear, your plugin already provides a global export UMD module by default.

Current state

  • UMD namespace: window["grapesjs-preset-newsletter"] (current UMD naming - source)
  • NPM namespace: npm install grapesjs-preset-newsletter
  • Grapes Plugin namespace: plugins: ['gjs-preset-newsletter']

Plugins can use either plugins: [window["grapesjs-preset-newsletter"]] or plugins: ["gjs-preset-newsletter"]

Proposed state

If you embraced plugins as functions, you would remove 1 of your 3 namespaces.

    plugins: [window.grapesjsPresetNewsletter]

Ideally your plugins and boilerplate would use a more sane UMD export.

  • UMD namespace: window["grapesjs-preset-newsletter"] window.grapesjsPresetNewsletter (better UMD naming)
  • NPM namespace: npm install grapesjs-preset-newsletter
  • Grapes Plugin namespace: plugins: ['gjs-preset-newsletter']

@artf
Copy link
Member

artf commented Aug 19, 2018

Thanks for the suggestion, Logan. Just to be clear, with the proposed state UMD namespace implies the plugin developer to define explicitly the global, eg.

const myPlugin = editor => { ... };
window.myPlugin = myPlugin;
export default myPlugin;

correct?
BTW, to be honest, I didn't even remember the global definition made by UMD wrapper, so in that case, when you ask for plugins: ["gjs-preset-newsletter"] instead of just looking for it inside grapesjs.plugins we can also check inside window... what do you think?

@loganvolkers
Copy link
Contributor Author

const myPlugin = editor => { ... };
window.myPlugin = myPlugin;
export default myPlugin;
correct?

Not quite correct. Webpack will turn export default myPlugin into window.myPlugin = myPlugin;.

There should be no need to ever manually add library to window in modern JS anymore, that should always be handled by webpack, or rollup, or parcel.

BTW, to be honest, I didn't even remember the global definition made by UMD wrapper, so in that case, when you ask for plugins: ["gjs-preset-newsletter"] instead of just looking for it inside grapesjs.plugins we can also check inside window... what do you think?

So plugins: ["gjs-preset-newsletter"] would be equivalent to plugins: window["gjs-preset-newsletter"]?

That seems reasonable to me.

@artf
Copy link
Member

artf commented Aug 23, 2018

So plugins: ["gjs-preset-newsletter"] would be equivalent to plugins: window["gjs-preset-newsletter"]?

I'd say more like this plugins: [ window["gjs-preset-newsletter"] ], the plugins options should always be an array

In that case, for the next release, I'll add the check inside the window and, later, update the grapesjs-plugin-boilerplate to clean it from peerDependencies

@lock
Copy link

lock bot commented Sep 17, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot added the outdated label Sep 17, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Sep 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants