Skip to content

Latest commit

 

History

History
243 lines (177 loc) · 7.06 KB

assets.md

File metadata and controls

243 lines (177 loc) · 7.06 KB

Importing Assets

Images, stylesheets and other assets are an important part of any web application. These things are integrated right into imba without any need for external bundlers like webpack or rollup.

Importing stylesheets

Even though you can style all of your app using the imba css syntax you might want to import external stylesheets as well. Import these just like you would import any other file.

import './assets/normalize.css'

tag App
	# ...

In the example above, the content of the normalize.css file will automagically be imported and bundled alongside your other styles.

You can also import the css generated by imba via a non-standard src attribute on the style element. This is especially useful for ssr applications where you don't want to ship your rendering code to the client, but obviously want the styles:

import {App} from './app'
app.get(/.*/) do(req,res)
	res.send String <html>
		<head>
			<title> "Application"
			<style src='./app'>
		<body> <App>
global css
	body bg:gray2 # ...

export tag App
	<self>
		<div[fw:bold]> "Welcome"

Importing images

Any relative url reference you have in your styles will be extracted, hashed, and included with your bundled code.

tag App
	<self> <div[ bg:url(./logo.png) ]>

Also, relative src attributes on <img> elements will automatically be handled as assets

tag App
	<self> <img src='./logo.png'>

If you want to reference and use these images from your code as well, you can import them:

import logo from './logo.png'

tag App
	<self> <img src=logo>

These imported assets even have valuable metadata added to them:

import logo from './logo.png'

logo.url # the unique hashed url for this image
logo.size # size of assets - in bytes
logo.hash # unique hash of the contents of the asset
logo.body # the actual contents of the asset - only available on server
logo.width # width of the imported image
logo.height # height of the imported image

tag App
	<self> <img src=logo width=logo.width>

You can also use the dynamic import syntax for assets:

const states = {
	open: import('./icons/alert-circle.svg')
	closed: import('./icons/check-circle.svg')
	archived: import('./icons/package.svg')
}

<div> for issue in issues
	<div>
		<img.icon src=states[issue.state]>
		<span> issue.title

You can even interpolate these dynamic asset imports in css:

const states = {
	open: import('./icons/alert-circle.svg')
	closed: import('./icons/check-circle.svg')
	archived: import('./icons/package.svg')
}

<div> for issue in issues
	<div>
		<.icon[ bg:{states[issue.state]} ]>
		<.title> issue.title

Importing svgs

SVGs can be imported and used just like other image assets described in the previous section. It does include some nice additional things though. You can use SVG images via css and the img-tag, but they really shine when you inline them in your html. Ie, if you want to use SVG images for icons you have to inline them to be able to change their color, stroke-width etc.

So, Imba adds a non-standard src attribute to svg elements, that magically inlines the actual content of the svg directly in your html.

<div>
	# the package.svg will now be inlined in this tag
	<svg src='./icons/package.svg'>

This also allows us to style the contents directly:

<div>
	# change color on hover
	<svg[c:gray6 @hover:blue7] src='./icons/package.svg'>
	# override stroke-width 
	<svg[stroke-width:4px] src='./icons/check.svg'>

Importing scripts

Imba will analyze the src attribute of script elements and automatically package these files for you. So a typical project with server and client code will follow this pattern:

# some express server ...
app.on(/.*/) do(req,res)
	res.send String <html>
		<head>
			<title> "Gobias Industries"
		<body>
			<script type="module" src="./client">
# some client code here

When you run imba server.imba in the above example, imba will discover the reference to client.imba and create a bundle for the client.imba entrypoint. Using esbuild in the background, bundling is so fast that it literally happens every time you start your server – there is no need for a separate build step.

Importing workers

Imba aims for zero-configuration bundling even with large projects. You can import scripts as separate assets via a special import syntax.

const script = import.worker './compiler'
# script is now an asset reference to the bundled compiler entrypoint.
script.url # reference to the unique/hashed url of this script
script.body # node only - actual contents of the bundle

const worker = new Worker(script.url)

To showcase how flexible and useful this is – on imba.io we are using a serviceworker to run examples. Serviceworkers need to be served from the directory / scope you want them to control, and their url need to be static. The asset urls generated by imba are usually hashed and put inside a special __assets__ folder:

const sw = import.worker './sw/service'
sw.url # /__assets__/sw/worker.JNA7FI8P.js

This url changes whenever the content changes and is nested inside an /__assets__/... prefix, both of which can be challenging for a serviceworker. So, our solution was to create a static route in our server, and just serve the asset directly:

app.get('/sw.js') do(req,res)
	const asset = import.worker('./sw/service')
	res.send asset.body

Custom imports

The import.worker syntax shown in the previous section is not a special syntax just for workers. In fact, the import.anything(...) is a general way to import something using a specific configuration. You can create such configurations in your imbaconfig.json. Imba comes with a few presets:

export const presets = 
	node:
		platform: 'node'
		format: 'cjs'
		sourcemap: true
		target: ['node12.19.0']
		external: ['dependencies','!imba']
		
	web:
		platform: 'browser'
		target: ['es2020','chrome58','firefox57','safari11','edge16']
		sourcemap: true
		format: 'esm'
		
	iife:
		extends: 'web'
		format: 'iife'
		
	client:
		extends: 'web'
		splitting: true
		
	worker:
		format: 'esm'
		platform: 'worker'
		splitting: false

Most of the properties map directly to esbuild options, with some additions for imba specific things. Configuration options will be explained in more detail before final 2.0 release. In most projects you will not need to think about or tweak these configs.

Future plans

Glob imports

We are working on smart glob imports for a future release.

import icons from './feather/*.svg'

# contains all matching assets:
icons.check
icons.circle
...

This will also work directly in src paths, like:

<div> for issue in issues
	<div>
		<svg src="./icons/{issue.state}.svg">
		<div.title> issue.title

Importing wasm

Will be part of a future release.