Skip to content

Managing Frontend Assets

Important Locations

Assets are managed by our in-house prism bundler. Most assets exist under ./assets/local-assets/.

Note

The prism bundler itself exists as a composer package. The node source exists in ./vendor/iww/prism/bin/. When starting the container for the first time, npm install will automatically run in this subdirectory, which uses ./.prism.settings.mjs in the root of the project to configure itself.


Build Commands

To build the assets, you can run the following command:

ddev build

To ignore the build cache and rebuild the assets from scratch, you can run the following command:

ddev rebuild

Our asset manager supports live development, which means that many changes can be shown in real time without needing to rebuild. You can run the asset dev server with the following command:

ddev dev

Live Reload Behavior

Reactive components will update in place, while updates that require twig rendering changes will refresh the screen.

Deployment

This live asset server is intended to reduce friction while developing the frontend locally, but asset changes will still need to be built before deploying to production.


Asset Types

When built, all assets are mapped to a manifest file located in ./public/bundle-prism/manifest.prism.json. You can refer to this manifest to see the path of each asset. The asset types supported are documented below:

The primary entry points for the web frontend and admin panel can be found in ./assets/app.ts and ./assets/admin.ts respectively. These entry points load the corresponding stylesheets other assets.

Adding more entry points

If you want to add or edit entry points, you can do so in ./.prism.settings.mjs.

All images under ./assets/local-assets/images/ will be processed and optimized and can be used in your twig templates. You can implement them by using the prism() function in your twig template. SVGs will render an <svg> component, while other image types will return the src attribute to use.

Twig

{# SVG images generate an <svg> #}
{{ prism('images/logo.svg') }}

{# other types returns an src attribute #}
<img src="{{ prism('images/logo.png') }}" alt="Logo">

All svg files under ./assets/local-assets/favicons/ will generate a favicon bundle. You can implement them in your twig template by placing them in the <head> section of your HTML. These favicon bundles include all necessary favicon sizes and types for all platforms. You can fine tune favicon settings in ./.prism.settings.mjs.

Twig

<head>
    {{ prism('favicons/web.svg') }}
</head>

Global SASS files under ./assets/local-assets/sass/ will be processed and compiled into CSS files if they are imported into an entry point.

Twig

<link rel="stylesheet" href="{{ prism('sass/main.scss') }}">

Tailwind

The UI is predominantly built with Tailwind CSS. By default you will find tailwind configuration amongst the SASS files.

MJML files under ./assets/local-assets/mjml/ will be processed and converted into twig templates located in ./templates/email. You can use these templates to generate HTML emails from PHP.

PHP

<?php
$email = (new TemplatedEmail())
    ->htmlTemplate('email/some_template.html.twig')
    ->context([
        'some_variable_name' => 'some_value',
        'some_other_variable_name' => 'some_other_value',
    ])

React application files are located in ./assets/local-assets/react/*.tsx. You can control the version of react to compile with in ./settings.prism.mjs. React application must first be registered in your entry point, and then rendered in your twig template.

1. Registering React Application

You will need to register your react application in your entry point file. Keep the name you give your application handy, as you'll need it to render the application in your twig template and to hydrate initial data.

Typescript

import { reactDOM } from "@local/ts/lib/react-dom-loader";
import MenuBuilderApp from "@local/react/MenuBuilderApp";

// ...

try {
    reactDOM.registerComponent({
        component: MenuBuilderApp,
        name: "MenuBuilderApp",
    });
} catch (e) {
    console.error(e);
}

2. Rendering Registered Applications

Using the name you provided when registering the application, you can render the application with the following dom markeup:

Twig

<div data-react="MenuBuilderApp"></div>

3. Initial Data Hydration

There are 3 ways to provide initial data to your react application. These will be merged together with the following priority:

Supply props when registering your component:

Typescript

reactDOM.registerComponent({
    component: MenuBuilderApp,
    name: "MenuBuilderApp",
    props: {
        someProp: "someValue",
        someOtherProp: "someOtherValue",
    },
});

Supply data-props attribute with a json string value when rendering your component:

Twig

<div
    data-react='MenuBuilderApp'
    data-props='{"someProp":"someValue","someOtherProp":"someOtherValue"}'>
</div>

Supply a global variable on the window object before rendering your component:

Typescript

window['react']['MenuBuilderApp'] = {
    someProp: "someValue",
    someOtherProp: "someOtherValue",
};