Integrating with JavaScript
This guide explains how to integrate JavaScript into your Utopia application.
Using Import Maps
Import maps provide a modern way to manage JavaScript module dependencies. Utopia includes built-in support for import maps through the class Utopia::ImportMap class.
Installing JavaScript Libraries
First, install the library using npm:
$ npm install jquery
Copy the distribution files to public/_components:
$ bundle exec bake utopia:node:update
This will copy the library's distribution files (typically from node_modules/*/dist/) to your public/_components/ directory, making them available for local serving.
Creating the Import Map
Create a global import map in lib/my_website/import_map.rb:
require "utopia/import_map"
module MyWebsite
IMPORT_MAP = Utopia::ImportMap.build(base: "/_components/") do |map|
map.import("jquery", "./jquery/jquery.js")
end
end
Then load this in lib/my_website.rb:
require_relative "my_website/import_map"
Adding to Your Pages
Add it to your page template (pages/_page.xnode), using relative_to to adjust paths for the current page:
<html>
<head>
#{MyWebsite::IMPORT_MAP.relative_to(request.path + "/")}
</head>
<body>
<!-- Your content -->
</body>
</html>
Using the Library
Once the import map is set up, you can import and use the library in your scripts:
<script type="module">
// <![CDATA[
import $ from 'jquery';
$(document).ready(function() {
console.log("jQuery is ready!");
});
// ]]>
</script>
Advanced Import Map Features
Using CDN URLs
Import maps support direct CDN imports without downloading files:
IMPORT_MAP = Utopia::ImportMap.build do |map|
map.import("react", "https://esm.sh/react@18")
map.import("vue", "https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.js")
end
Nested Base URLs
You can organize imports from different sources using nested with(base:) blocks:
IMPORT_MAP = Utopia::ImportMap.build do |map|
# Local components
map.with(base: "/_components/") do |local|
local.import "app", "./app.js"
end
# CDN imports
map.with(base: "https://cdn.jsdelivr.net/npm/") do |cdn|
cdn.import "lit", "lit@2.7.5/index.js"
cdn.import "lit/decorators.js", "lit@2.7.5/decorators.js"
end
end
Subresource Integrity
Add integrity hashes for enhanced security:
IMPORT_MAP = Utopia::ImportMap.build do |map|
map.import("react", "https://esm.sh/react@18", integrity: "sha384-...")
end
Scoped Imports
Use scopes to resolve imports differently based on the referrer URL (the page or module location where the import is being made):
IMPORT_MAP = Utopia::ImportMap.build do |map|
map.import("utils", "/utils.js")
# When importing from any page under /admin/, use a different utils module
map.scope("/admin/", {"utils" => "/admin/utils.js"})
end
When you're on a page at /admin/dashboard and you import "utils", it will resolve to /admin/utils.js. On other pages, it resolves to /utils.js.
Traditional JavaScript
You can also use JavaScript by embedding it directly into your HTML, or by creating a JavaScript source file and referencing that.
Embedding Code
When embedding JavaScript directly in XRB templates, wrap the code in CDATA comments to prevent XRB's parser from interpreting special characters like <, >, and &:
<html>
<body>
<script type="text/javascript">
// <![CDATA[
console.log("Hello World")
// ]]>
</script>
</body>
</html>
External Script
In script.js:
console.log("Hello World")
In your HTML view:
<html>
<body>
<script type="text/javascript" src="script.js"></script>
</body>
</html>