8. Client assets
Introduction
When working with the new template system (and the underlaying component functionality), you will eventually run into cases or components that require client assets; Javascript, CSS or images.
Below we will go through a shortlist of adding and using those.
Images
Using images in Adventure template system is very similar to using images in Rooty based designs. It's important to note there are different ways to access and use images in designs.
- Images loaded thru resources (controllers in form of collections and entities) ie. product images.
- Images related to design; Loaded thru template settings or added directly as a design dependency ie. solution logo.
Entity images
These are handled thru the FilesController class, which is used to fetch images related to entities like
products, categories, etc. We've made them a bit easier to use using the component system and the business logic
functions, located in /src/functions/*.tpl.
An example of this is the /src/functions/product.tpl that has functions to fetch product images or even the featured
product image, the main image of the product, used in product lists or product collections, like cart:
{function getProductImages } ... {/function}
{function getFeaturedProductImage } ... {/function}
The updated logic for Adventure is the new component composit {Image}, that will accept an image object and
output the markup for an image. It even handles null exceptions, where there is no image to display. But all this
will be handled generally by the component, so you don't have to worry about it. We use this component extensively in
the Adventure design, so you can see how it works in practice.
To handle breakpoints, image srcset and responsive images, we have added a few business logic functions to the
/src/functions/image.tpl file, that can be used to format and size a entity image correctly, based on the design
setup.
{function getImageSrcsetData } ... {/function}
Design images
Design images are images that are not related to any entity, but rather to the design itself. These images can be added to a Adventure design much the same way as in a Rooty design. The only difference is that Adventure doesn't have a modifier for the solution path. You have to go through the platform utilities so long as the image is added to the design folder. External images will have to linked traditionally.
{$solution = $Platform->import("solution")}
<img
src="{$solution->getDomainStatic()}/sample.png"
alt="Sample image"
>
SVG
With Adventure we have added an icon component that is a basic SVG library. It's a small collection of SVG icons that can be used in your designs thru the {Icon} component. To get an overview of the icons available, look into the /src/elements/Icon/svg/ folder. The example below shows how the icon component could be used:
{Icon
name="log-out"
size="large"
}{/Icon}
Checkout /src/elements/Icon/Icon.tpl for more information about the supported properties for {Icon} component.
CSS
Much like images, we have different types of styling that can be added to the design.
- General, global or external styles, loaded traditionally.
- Component specific styles, that are added when a component is loaded.
Traditional styles
These styles can be added as a <link rel="stylesheet" type="text/css" href="..."> tag or as inline styling with
<style>...</style> tag. The only caveat is that styling tags (<link ...> or <style>...</style>) added inside
a component file, will only be added when or if the component is loaded.
{$solution = $Platform->import("solution")}
<link
rel="stylesheet"
type="text/css"
href="{$solution->getDomainStatic()}/sample.css"
>
<style>
.sample {
color: currentColor;
}
</style>
Component styles
For components, we've added a support component {Style}. {Style} supports linking and inline styles. If the
{Style} component has a src property it will be added as a link by appending it as <link ..> to <head>
element. If multiple {Style} with the same src
property are added, it will only be added to the final output once. To achieve the samething for inline styles, you will
need to add am id property. We usually use the component name for the id property. If your component requires
unique styling for each render, consider using uniqueId on the HTML platform utility.
{Style src="./Sample.css"}{/Style}
{Style id="Sample"}
.sample {
color: currentColor;
}
{/Style}
Javascript
Much like images and styles, we have different types of script that can be added to the design.
- General, global or external scripts, loaded traditionally.
- Component specific scripts, that are added when a component is loaded.
Traditional scripts
These scripts can be added as a <script src="..."> tag or as inline script with
<script>...</script> tag. The only caveat is that script tags added inside
a component file, will only be added when or if the component is loaded.
{$solution = $Platform->import("solution")}
<script
src="{$solution->getDomainStatic()}/sample.css"
></script>
<script>
console.log("sample");
</script>
Component scripts
For componets, we've added a support component {Script}. {Script} supports linking and inline scripts. If the
{Script} component has a src property it will be added as a link. All script links are appended to the page
content, by adding them as a list right before </body> element. Any script that is added with the component
will be added as a module, using type property; type="module". If multiple {Script} with the same src
property are added, it will only be added to the final output once. To achive the samething for inline scripts, you will
need to add an id property. We usually use the component name for the id property. If your component requires
unique styling for each render, consider using uniqueId on the HTML platform utility.
{Script src="./Sample.js"}{/Script}
{Script id="Sample"}
console.log("sample");
{/Script}
Using Javascript modules (import)
Javascript dependencies and modules in Adventure are managed thru importmap and the
@root keyword. This means you can import JavaScript modules directly in your components or scripts without being
concerned about the file paths. The importmap is built and output in the final document based on component usage.
The importmap feature allows you to define module paths in a centralized manner, enabling cleaner and more maintainable imports in your JavaScript code. It eliminates the need for relative paths by mapping module names to their respective file locations.
Below is an example of how the debouce function from elements is loaded and used in a different component:
import { debounce } from '@root/elements/debounce.js'
debounce( () => {
...
}, 1500)
Testing and linting
In the root package.json file the following scripts can be executed:
-
test- Starts Jest to unit test all files -
test:watch- Jest to watch for file changes, and test those files -
lint- Will show all files with lint errors using stylelint and eslint -
lint:js- Shows lint errors for ESLint -
lint:css- Shows lint errors for Stylelint -
lint:fix- Will try to fix all lint and formatting errors -
lint:js:fix- Will try to fix JavaScript lint errors -
lint:css:fix- Will try to fix CSS lint errors -
format:js- Errors out formatting issues in JavaScript using prettier -
format:js:fix- Will try fix the formatting issues