Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add 'No-Build Workflows' doc, focusing on importmaps (for now) #1175

Merged
merged 5 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions content/en/guide/v10/importmaps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
name: Import Maps
description: 'Import maps are a new feature in JavaScript that are especially useful for no-build workflows.'
---

# Import Maps

Import maps are a new feature in JavaScript that are especially useful for no-build workflows.

An [Import Map](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) is a newer feature
that allows you to control how browsers resolve module specifiers, usually to convert bare specifiers such as `preact`
to a CDN URL like `https://esm.sh/preact`. While many do prefer the aesthetics import maps can provide, there are also
real advantages to using them, such as better control over dependencies and solving the issues that come with HTTP imports.

This isn't to say you need import maps, but for those choosing to forgo build tooling, they are a great option that can help
solve some issues such as dependency duplication, versioning, and allow use of more intelligent CDNs, without giving up control.

## Basic Usage

[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) has a great deal of information on how to
utilize import maps, but a basic example looks like the following:

```html
<DOCTYPE html>
<html>
<head>
<script type="importmap">
{
"imports": {
"preact": "https://esm.sh/[email protected]",
"htm/preact": "https://esm.sh/[email protected]/preact?external=preact"
}
}
</script>
</head>
<body>
<div id="app"></div>

<script type="module">
import { render } from 'preact';
import { html } from 'htm/preact';

export function App() {
return html`
<h1>Hello, World!</h1>
`;
}

render(html`<${App} />`, document.getElementById('app'));
</script>
</body>
</html>
```

We create a `<script>` tag with a `type="importmap"` attribute, and then define the modules we'd like to use
inside of it as JSON. Later, in a `<script type="module">` tag, we can import these modules using bare specifiers,
similiar to what you'd see in Node.

> **Note:** We use `?external=preact` in the example above as https://esm.sh will helpfully provide the
> module you're asking for as well as its dependencies -- for `htm/preact`, this means also providing `preact`.
> However, Preact, and many other libraries, need to be used as singletons (only a single active
> instance at a time) so this creates a problem.
>
> By using `?external=preact`, we tell `esm.sh` that it shouldn't provide a copy of `preact`, we can handle
> that ourselves. Therefore, when the browser goes to execute `htm/preact`, it will use our importmap to find
> `preact` and use the same instance as the rest of our code.

## Recipes and Common Patterns

While not an exhaustive list, here are some common patterns and recipes you may find useful when working with
import maps. If you have a pattern you'd like to see, let us know! //TODO: Add GH issues link

For these examples we'll be using https://esm.sh as our CDN -- it's a brilliant option is a bit more flexible
than some others, but by no means are you limited to it.

### Preact with Hooks, Signals, and HTM

```html
<script type="importmap">
{
"imports": {
"preact": "https://esm.sh/[email protected]",
"preact/": "https://esm.sh/[email protected]/",
"@preact/signals": "https://esm.sh/@preact/[email protected]?external=preact",
"htm/preact": "https://esm.sh/[email protected]/preact"
}
}
</script>
```

### Aliasing React to Preact

```html
<script type="importmap">
{
"imports": {
"preact": "https://esm.sh/[email protected]",
"preact/": "https://esm.sh/[email protected]/",
"@mui/material": "https://esm.sh/@mui/material?alias=react:preact/compat,react-dom:preact/compat&external=preact"
}
}
</script>
```

...or, alternatively...

```html
<script type="importmap">
{
"imports": {
"preact": "https://esm.sh/[email protected]",
"preact/": "https://esm.sh/[email protected]/",
"react": "https://esm.sh/[email protected]/compat",
"react/": "https://esm.sh/[email protected]/compat/",
"react-dom": "https://esm.sh/[email protected]/compat",
"@mui/material": "https://esm.sh/@mui/material?external=react,react-dom"
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just push for this one instead of the ?alias think. I've found that people are less likely to shoot themselves in the foot with this looking at past support questions in Fresh.

Copy link
Member Author

@rschristian rschristian Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, sounds good.

Any other situations and/or examples you want to see added to help Fresh people? I realize there's been a fair bit of struggling over there so if our docs could help at all, that'd be great. I did take a quick skim but it seemed to (largely) be people struggling with specific dependencies rather than anything major conceptually.

</script>
```

Both are equivalent, using slightly different methods. If you're using the many React libraries, the second
method may be preferable, as it avoids the need to alias in every CDN URL, but ultimately, it's personal taste.
6 changes: 6 additions & 0 deletions src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,12 @@
{
"path": "/typescript",
"name": "TypeScript"
},
{
"path": "/importmaps",
"name": {
"en": "Import Maps"
}
}
]
}
Expand Down