[![Actions Status](https://github.com/rshingleton/Mojolicious-Plugin-WebComponent/actions/workflows/test.yml/badge.svg)](https://github.com/rshingleton/Mojolicious-Plugin-WebComponent/actions) # NAME Mojolicious::Plugin::WebComponent - An effort to make creating and using custom web components easier # SYNOPSIS Web Components is a suite of different technologies allowing you to create reusable custom elements — with their functionality encapsulated away from the rest of your code — and utilize them in your web apps. ([https://developer.mozilla.org/en-US/docs/Web/API/Web\_components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components). Mdn Web Docs.) # DESCRIPTION Web Components can be useful in building small, reusable components in a web application. This plugin is an effort to make developing web components in Mojolicious a little easier. It facilitates the development of scripts and Mojolicious html templates to provide custom components that can also be templated using Mojolicious templating features. In doing this we can combine some server side rendering and dynamic rendering. This plugin provides an easier way to inject Mojolicious templates into custom web component scripts. By using the component helper, the scripts and templates are tied together in the WebComponent controller before being sent to the rendered web page. In a Mojo App my $wc = $self->plugin(WebComponent, {}); In a Mojo Lite App plugin WebComponent => {}; In the HTML head # in the html header %= component 'my-component' Minimal component script implementation, /assets/js/components/my-component.js class MyComponent extends HTMLElement { constructor() { super(); } // let tmpl can be defined here inline or provided in an HTML template // of the same name as the script file let tmpl; } customElements.define("my-component", MyComponent); HTML template association, /templates/components/my-component.html.ep
This is a custom web component
# Example The following example is a web component that consists of a JavaScript file and an associated template. This example also uses alpine.js to provide some responsive updates via a recurring update routine. #### app The base application is taking advantage of [Mojolicious::Plugin::WebComponent](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AWebComponent) and [Mojolicious::Plugin::AssetPack](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AAssetPack) sub startup($self) { $self->renderer->cache->max_keys(0) if $self->mode eq 'development'; $self->plugin(AssetPack => { pipes => [ qw(Sass Css JavaScript Combine Fetch) ] }); $self->asset->store->paths($self->static->paths); $self->plugin(WebCojsDeferredmponent => { path => "$path/component" }); my @css =( "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css", "assets/scss/main.scss" ); my @js =( "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.min.js", "assets/js/main.js" ); my @jsDeferred =( "https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.13.5/cdn.min.js" ); $self->asset->process("app.css" => @css); $self->asset->process("deferred.js" => @jsDeferred); $self->asset->process("app.js" => @js); # Router my $r = $self->routes; # default route to controller $r->any('/')->to('default#index')->name('index'); } #### base layout <%= title %> %= asset "app.css" %= asset "deferred.js", defer => undef %= asset "app.js" %= component 'system-hosts'
<%= content %>
#### index page In the index page we reference our custom component <system-hosts>. The updates are done in the [alpine.js](https://alpinejs.dev/) script using a periodic update timer. This could also be done with websockets, long polling using axios, or other ajax methods with periodic interval updates. % layout 'default'; % title 'Welcome';
#### /public/assets/js/components/system-hosts.js Templates processing is handled in the WebComponents controller. By default, the associated html template will be processed by Mojolicious and then injected into the JavaScript replacing the "let tmpl;" with the processed html template structure. // Extend generic HTMLElement interface class SystemHosts extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({mode: 'open'}); // tmpl variable is generated server side if not provided as a local variable // the tmpl variable will be replaced server side by the Mojolicious WebComponent // plugin let tmpl; shadowRoot.appendChild(tmpl.content.cloneNode(true)); } connectedCallback() { const {shadowRoot} = this; // here we attach alpine to the component dom document.addEventListener("alpine:initialized",()=>{ Alpine.initTree(this.shadowRoot) }) } } // the define call is where our component gets exported so we can use a element customElements.define('system-hosts', SystemHosts); #### /templates/components/system-hosts.html.ep This is the template for our custom <system-hosts> web component. In the plugin we also provide any request parameters in a params hash so that they can be templated by the Mojolicious templating system if present. In this example, the <%= $params->{system} %> will print out the system name param if available in the controller.
Loading Host Data...
<%= $params->{system} %> HOSTS:
# CONFIGURATION # full mojo app my $wc = $self->plugin(WebComponent, \%conf ); # or mojo lite plugin WebComponent => {}; ## path default: /component The path setting can be used to set the base url for the controller. This is useful for reverse proxy settings or if you want to modify the controller path. The controller pattern is: $path/:req/*component ## javascript\_path default: <app>/<public-dir>/<assets-dir>/js/components The template\_path setting allows the user to set the directory within the default Mojolicious public location where the WebComponent script files are located. ## template\_path default: <app>/<template-dir>/components The template\_path setting allows the user to set the directory within the default Mojolicious templates location where the application can locate and process template fragments associated with the WebComponent. # HELPERS ## component This component helper is used in a template to generate a script tag for each request. The script tag is associated with a matching JavaScript file, by default found in public/assets/js/components # app/templates/layouts/default_head.html.ep <%= title %> %= asset "app.css" %= asset "app.js" %= component 'my-web-component' The generated script tag will include a reference to the original request ID, the provided component script name, and parameters from the original request. # example tag generation ### Helper Options #### template The only parameter currently supported that can be passed to the helper is "template". By default the html template file associated with the script will match the component name passed to the helper. In this example, my-web-component maps to the the script file /public/assets/js/components/my-web-component.js and the html template file /templates/components/my-web-component.html.ep. If you want to use a different template name for some reason, you can it as a hash entry to the component helper %= component 'my-web-component', { template => 'my-special-template' } This would map my-web-component.js to my-special-template.html.ep. Passing a undef to the template key will cause the plugin to skip any template processing and assume that the html content is embedded in the JavaScript file already. # ROUTES This plugin creates a route to return the WebComponent script to the application. The default route is /component/:reqId/\*component. The path configuration setting can be passed during initialization to modify the base path of the controller. ## /component/:reqId/\*component This is generated by the component helper and is a script tag associated with the custom component url. For example, the helper generates <script src='/component/kbB7s76PmaY9/my-component.js'></script>. Navigating to the url, /component/kbB7s76PmaY9/my-component.js, will return the templated JavaScript component file. # METHODS ## register $self->register($app, \%config); Used to register the plugin in the application. `%config` can contain: - helper Name of the helper to add to the application. Default is "component". # SOURCE [https://github.com/rshingleton/Mojolicious-Plugin-WebComponent](https://github.com/rshingleton/Mojolicious-Plugin-WebComponent) # SEE ALSO [Mojolicious::Plugin::AssetPack](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AAssetPack). # LICENSE Copyright (C) R.Shingleton. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. # AUTHOR Russell Shingleton