ponzu icon indicating copy to clipboard operation
ponzu copied to clipboard

Static assets in Ponzu addons

Open nilslice opened this issue 7 years ago • 12 comments

Wanted to include others who might be interested in the discussion. Originally posted here on the @aleksen's repo for a Markdown editor input addon: https://github.com/aleksen/smdeditor/issues/1

Just wondering if it would be useful for Ponzu addon developers to be able to rely on a defined an "open ended" path for serving static assets. In SMDeditor addon, the JS for the markdown parser is hotlinked from an external source, which is fine of course. But, if developers knew that static assets in their addons could be served from ponzu-server, would it be preferable?

For example, what if we were to add a new handler in the admin server such as: http.Handle("/admin/addons/", fileServer), which would serve anything in the addons/ directory? Maybe 404ing any .go extension so internal source isn't viewable if the observer was able to correctly guess filepaths. Is there anything else potentially risky to serve out of these addon repo directories?

This way you could add files like: github.com/aleksen/smdeditor/simplemde.min.js & github.com/aleksen/smdeditor/simplemde.min.css directly into your repo and link them reliably from your addon. You'd then be able to link your assets like:

<script src="/admin/addons/github.com/aleksen/smdeditor/simplemde.min.js"></script>

Alternatively, it would be possible to register these static assets so they are loaded in their proper location in the HTML document head after other Ponzu admin dependencies. We would need to change the API a bit, but it's something to consider.

nilslice avatar Jun 16 '17 23:06 nilslice

I hit both (static resources+head) almost immediately when I stared using ponzu.

IMHO creating few routes in plugin is not that big of a deal for a plugin authors. But if ponzu had methods exposed for doing so in ponzu standardised way, it could be easily upgraded/changed in future.

Also, I get the creeps from idea of seeing url-to-my-internal-repo in url of static resources. There has to be better way of putting plugins to ponzu folder structure and not expose all that?

<script src="/admin/addons/smdeditor/simplemde.min.js"></script>

I am working on a PR that would enable custom html/javascript in <head>. Currently figuring out where (and when) is the right place to put it, because plugins init() 'n' stuff.

edit: also, https://github.com/aleksen/smdeditor is ok as an idea, however it has conceptual bug. The loaded var works only on 1st runtime start, not on first usage on page. There must be better way to inject stuff in head of admin cms html.

guycalledseven avatar Jun 18 '17 20:06 guycalledseven

Excellent -- thank you for the feedback.

IMHO creating few routes in plugin is not that big of a deal for a plugin authors. But if ponzu had methods exposed for doing so in ponzu standardised way, it could be easily upgraded/changed in future.

I agree, there should be some way for developers to configure static routes.. in order to remove the repo path from the html source, we'd probably need to have some kind of mapping to match the identifying part of the asset URL to it's location within the addons directory. ex:

// the map key defines the route (would be prepended with /addons/static/ when the
// func is called and route is registered. the value is the location within /addons/ on disk
addon.StaticAssets(map[string]string{
  "smdeditor/simplemde.min.js": "github.com/aleksen/",
  "smdeditor/simplemde.min.css": "github.com/aleksen/",
})

This concept both registers the addons, and stores routing info. I suppose it would be good to have some kind of glob/wildcard in case a user wanted to register all files inside a directory. ex:

addon.StaticAssets(map[string]string{
  "smdeditor/static/*": "github.com/aleksen/",
})

StaticAssets would look for the *, and then register each file in that directory to the same "github.com/aleksen" disk path supplied as it's value in the map -- this could skip files with .go extensions or other possible security risks. If you have a more elegant way to do it and achieve hiding the local path including username/repo info please lmk!

One thing that this doesn't take into account is the file's contents.. Do we rely on the file extension to determine how the asset is added to the

i.e. JS => <script>, CSS => <link>, and so on for other media.

I am working on a PR that would enable custom html/javascript in <head>. Currently figuring out where (and when) is the right place to put it, because plugins init() 'n' stuff.

Awesome! Please do a pull from master since I added some new code recently and I noticed your fork is behind. Lmk if you'd like to share your progress; I'd love to take a look. I imagine the StaticAssets func could also create the HTML, and append it to a addon package variable which could be exported and used when creating the admin UI

element.

nilslice avatar Jun 19 '17 21:06 nilslice

Yes I think with patterns you covered all use cases that I can think of right now. 👍

Would this be a part of addon signature or additional call? I understand signature is optional right now, but having this stuff in one place could be nifty. Can't think of a reason why would anybody change location of static files multiple times inside addon.

One thing that this doesn't take into account is the file's contents.. Do we rely on the file extension to determine how the asset is added to the i.e. JS =>

Serving content type based on file name will backfire. IMHO slightly better way would be by reading local file and analysing it with http.DetectContentType.

I imagine the StaticAssets func could also create the HTML, and append it to a addon package variable which could be exported and used when creating the admin UI element.

IMHO there is too much use cases to cover them all in ponzu admin html builder. I would rather use my own html template with markup, javascript, css and load/inject that instead.

For example, how html for multiple reference options (eg. products:"[]@product") is generated right now, is not working well for me. From ux perspective one large select (size=x multiple) would fit better than multiple select/options stacked one after another. If you start adding configurable html options to ponzu html builder things could go out of hands, next thing you know - you are building a golang html builder.

guycalledseven avatar Jun 20 '17 23:06 guycalledseven

Great -- thanks for your help thinking it through.

Would this be a part of addon signature or additional call? I understand signature is optional right now, but having this stuff in one place could be nifty. Can't think of a reason why would anybody change location of static files multiple times inside addon.

Maybe there should be an added field to addon.Meta which is used to track the static resources. The field would either be a []byte of HTML link/script/etc tags based on the assets - which is what I meant by rendering HTML (so it's only done once, rather than on each page load), or a map resembling the args to StaticAssets. This way the developer of the addon would follow this flow:

var meta = &addon.Meta{
	PonzuAddonName: "My Addon",
	PonzuAddonAuthor: "ACME Co"
	PonzuAddonAuthorURL: "https://github.com/acmeco/myaddon",
	PonzuAddonVersion : "1.0",
}

var _ = meta.StaticAssets(map[string]string{ // StaticAssets would return an error value
  "smdeditor/static/*": "github.com/aleksen/",
})

var _ = addon.Register(meta, func() interface{} { return new(MyAddon) }

The StaticAssets method needs to be associated with the addon anyways, so it might make sense to put it on the Meta type. Didn't think of it initially... but a simple exported StaticAssets func from the addon package wouldn't work well.

Serving content type based on file name will backfire. IMHO slightly better way would be by reading local file and analysing it with http.DetectContentType.

Excellent. Wasn't aware of that func, and it will definitely be safer.

IMHO there is too much use cases to cover them all in ponzu admin html builder. I would rather use my own html template with markup, javascript, css and load/inject that instead.

Sorry, I meant the HTML to be injected into the

, not the markup of the addon if there is any. I believe this is what you said your PR is regarding, and mentioned it so you could reliable get the static assets from the addon's registration data and pull them into the HTML when rendering that view. Does that make sense? We could be talking about completely separate issues here! haha

For example, how html for multiple reference options (eg. products:"[]@product") is generated right now, is not working well for me. From ux perspective one large select (size=x multiple) would fit better than multiple select/options stacked one after another. If you start adding configurable html options to ponzu html builder things could go out of hands, next thing you know - you are building a golang html builder.

Completely agree. For many use cases the repeaters shipped with Ponzu isn't ideal. I just tried to re-use as much of the logic as possible to get it launched. Could certainly see a nice ajax / async loading multi-select for reference repeaters, and thus the beauty of addons!

nilslice avatar Jun 20 '17 23:06 nilslice

@guycalledseven - hey hope all is well! just checking in with you to see if you had any thoughts on getting this featured added, and further locking down the addons API.

nilslice avatar Sep 07 '17 19:09 nilslice

Ponzu is such a brilliant idea. Kudos @nilslice. I'm interested in this ticket too, mostly the need for Markdown brought me here.

zharley avatar Sep 15 '17 22:09 zharley

@zharley - thank you for the kind words, glad you are liking it!

It's great to have your interest on this -- finalizing the Addon APIs is something we need more eyes on. Just so you know, the 1.0 release is basically waiting on addons to be fully baked.

Would you share a bit about how you want to use Markdown? Is this to create / edit content inside an input within the Ponzu admin, like a editor.Richtext? Or, something where you want to take output from the Content APIs and render markdown client-side?

nilslice avatar Sep 15 '17 22:09 nilslice

Yes, I was going to use it to create / edit content inside an input within the Ponzu admin, like a editor.Richtext... exactly how smdeditor works, except for the issue mentioned above that the loaded var works only on 1st runtime start. Happy to be an extra pair of eyes as the Addon APIs evolve.

zharley avatar Sep 17 '17 01:09 zharley

@zharley, I just patched @aleksen's markdown editor addon, but until they merge the PR, you could probably just copy from https://github.com/nilslice/smdeditor/blob/f0de6fd834888eb4ff3c0b9b1273116bd8b0eb08/smdeditor.go

Let me know if that works? I'll get a more formal discussion going around the Addons API when I have a bit more free time, hopefully next week.

nilslice avatar Sep 17 '17 03:09 nilslice

Hi @zharley,

The addon was merged, so you can and run the following from your ponzu project:

$ go get -u github.com/aleksen/smdeditor
$ rm -rf addons/github/aleksen
$ ponzu add github.com/aleksen/smdeditor

You should then be able to replace the editor.Input func with smdeditor.Input, build and run.

The issue being discussed on this thread is focused mainly on an API to enable static assets (js/img/css, etc) for an addon to be served from ponzu directly, unlike the smdeditor which is referencing the assets from another server.

If you have any ideas or concerns about what has already been discussed between @guycalledseven and myself above, please share!

nilslice avatar Sep 17 '17 07:09 nilslice

OK great! Thank you. I'm also interested in addon development, so I'll continue to follow this conversation and chime in when I can.

zharley avatar Sep 18 '17 14:09 zharley

@zharley, as a good primer, take a look at the FB Scheduler addon which demonstrates how an addon can register itself with the CMS, and present some UI for configuration.

It's not licensed for commercial or personal use, but until it is, consider this a license to use it for learning.

If you create a new project to try it, make sure to run $ ponzu add github.com/bosssauce/fbscheduler and then import it from at least one content type. It's common for users to report that an addon isn't working, but have simply forgotten that it's a Go package and needs to be imported otherwise the compiler doesn't build it into the project.

nilslice avatar Sep 18 '17 15:09 nilslice