Browser
The app/browser
directory is where JavaScript files for the browser live. These JavaScript files can import other modules from your project as well as any installed packages that can run in the browser. Files in the app/browser
directory will be bundled to the /public/browser/
directory in your project and will be exposed the to browser at /_public/browser/
for loading by script tags.
<script type="module" src="/_public/browser/my-file.mjs"></script>
Add a browser bundle
Create a JavaScript file for the browser.
app
├── browser ........... browser JavaScript
│ └── index.mjs
└── pages ............. file-based routing
└── index.html
const message = document.getElementById('message')
message.innerHTML = '👋 Hello from your bundle!'
Source a bundle in a page
Add a script tag and load it from /_public/browser/index.mjs
<main>
<h1>My awesome page</h1>
<p id="message"></p>
</main>
<script type="module" src="/_public/browser/index.mjs"></script>
The /_public
endpoint is created for you so that Enhance can do the tedious work of replacing your authored file name with a fingerprinted one to avoid caching issues.
Share elements with the browser
Now that you get the basics of the browser bundle workflow let’s look at how you might share your elements with the browser for progressive enhancement.
Add a my-message element
Add the file app/elements/my-message.mjs
app
├── browser ........... browser JavaScript
│ └── index.mjs
├── elements .......... custom element pure functions
│ └── my-message.mjs
└── pages ............. file-based routing
└── index.html
Write a custom element pure function
Write a pure function for returning the HTML markup for the my-message.mjs
custom element.
export default function MyMessage({ html, state }) {
const { attrs={} } = state
const { message='' } = attrs
return html`<h1>${ message }</h1>`
}
Reuse your pure function in the browser
Import the my-message.mjs
element in the app/browser/index.mjs
file to reuse your pure function in the browser.
import MyMessage from '../elements/my-message.mjs'
class MyMessageElement extends HTMLElement {
constructor() {
super()
const templateID = `${this.tagName.toLowerCase()}-template`
const template = document.getElementById(templateID)
if (template) {
this.template = template
}
else {
this.template = document.createElement('template')
this.template.innerHTML = MyMessage({
html: this.html,
state: {}
})
this.template.setAttribute('id', templateID)
}
this.replaceChildren(this.template.content.cloneNode(true))
this.heading = this.querySelector('h1')
}
html(strings, ...values) {
return String.raw({ raw: strings }, ...values)
}
static get observedAttributes() {
return [ 'message' ]
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
if (name === 'message') {
this.heading.textContent = newValue
}
}
}
}
customElements.define('my-message', MyMessageElement)
Using Enhance Element
Same thing as above but with @enhance/element
import enhance from '@enhance/element'
import MyMessage from '../elements/my-message.mjs'
enhance('my-message', {
attrs: [ 'message' ],
render: MyMessage
})
Add the script to your page
All that’s left now is to add a script tag to app/pages/index.html
that sources your browser bundle.
<my-message message="Howdy!"></my-message>
<script type="module" src="/_public/browser/index.mjs"></script>
Changing the message
attribute will trigger an update to your Custom Element.
Try it out in dev-tools.
That’s it
Now you can use this built-in pattern for sharing elements with the browser and progressively enhancing your pages with JavaScript.