Vanilla JS in Hyperspan
Modern JavaScript has come a long way in the past decade or so. There is often no
need to use a client-side framework to add small bits of interactivity to your site or app.
Luckily, Hyperspan makes it easy to ship your own vanilla client-side JavaScript code to the
browser using import maps and <script type="module">
tags
(widely supported by all modern browsers).
Bring Your Own JavaScript (BYOJS)
To use your own JavaScript code in the browser, you first need to create a file that ends
with
.client.ts
. This tells Hyperspan to treat this file as a client-side module on
import. All examples in the docs assume you are using a app/clientjs
directory,
but you can put this file in any other directory and organize your code however you like as
long as it ends in .client.ts
.
For example, if you want to track RUM data with Datadog, you can create a file called
app/clientjs/datadog.client.ts
and add the following code:
import { datadogRum } from '@datadog/browser-rum'
export function initDatadog() {
datadogRum.init({
applicationId: process.env.APP_PUBLIC_DATADOG_APPLICATION_ID,
clientToken: process.env.APP_PUBLIC_DATADOG_CLIENT_TOKEN,
site: 'datadoghq.com',
});
}
Note: Variables prefixed with APP_PUBLIC_
will be replaced with their literal
string values. See the Environment Variables docs for details.
Using Your Own Client-Side Code
Once the file is created, you can import it and use it in any template, layout, or route
with the renderScriptTag
function like this:
import { createRoute } from '@hyperspan/framework';
import { html } from '@hyperspan/html';
import datadog from 'app/clientjs/datadog.client'; // Import the whole module
import { renderScriptTag } from '@hyperspan/framework/assets'; // Render the script tag
export default createRoute(() => {
return html`
<main>
<h1>Some Page Route</h1>
<p>Example content for a page route.</p>
${renderScriptTag(datadog, (module) => {
module.initDatadog();
})}
</main>
`;
});
The code above will:
- Compile your client-side TypeScript on
import
into an external JS file -
Add a reference to the compiled external file to an
importmap
on the page -
Render a
<script type="module">
tag on the page that imports your module and runs the optional callback to initialize the module. Any exports from the module will be available to your callback function.
You Can Always Use a <script>
Tag
For less complex use cases, you can always use a script
tag directly in your
template. Hyperspan templates are just HTML!
import { createRoute } from '@hyperspan/framework';
import { html } from '@hyperspan/html';
export default createRoute(() => {
return html`
<main>
<h1>Some Page Route</h1>
<p>Example content for a page route.</p>
<script>alert('Hello, world!');</script>
</main>
`;
});
If you want to write the script using TypeScript instead of inside a template string, you can define the function in the file and then render it as a string in the template before calling it. The compiler will transpile your code into JavaScript that will work in the browser before the template is rendered.
import { createRoute } from '@hyperspan/framework';
import { html } from '@hyperspan/html';
export default createRoute(() => {
return html`
<main>
<h1>Some Page Route</h1>
<p>Example content for a page route.</p>
<script>
// Use an IIFE because the name might change when minified!
(${showGreeting.toString()})('John');
</script>
</main>
`;
});
function showGreeting(name: string) {
alert(`Hello, ${name}!`);
}
Note: The major caveat to stringifying functions is that you can't use any dependencies or references to any other symbols in the file outside of the function itself. It's like copying the function and pasting it somewhere else.
This approach works suprisingly well for simple things, but if you need to use dependencies,
you should use the renderScriptTag
function instead (see above).