Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/dvinciguerra/middleman-importmap

Importmap extension port for Middleman
https://github.com/dvinciguerra/middleman-importmap

frontend importmaps middleman middleman-extension ruby rubygem

Last synced: 3 months ago
JSON representation

Importmap extension port for Middleman

Awesome Lists containing this project

README

        

# middleman-importmap

[![Maintainability](https://api.codeclimate.com/v1/badges/aab4c3c09d920639f962/maintainability)](https://codeclimate.com/github/dvinciguerra/middleman-importmap/maintainability)

An Importmap extension for Middleman.

## Install

**Add gem to `Gemfile`**

`gem 'middleman-importmap'`

## Usage

#### Activate extension in `config.rb`**

```ruby
activate :importmap
```

#### Create the `importmap.yml` file at middleman root path

```shell
$ cd middleman_project && touch importmap.yml
```

#### Add importmaps to file (example)

```yaml
imports:
"@hotwired/stimulus": https://unpkg.com/@hotwired/stimulus/dist/stimulus.js
```

The importmap.yml file keep the same structure of importmap in HTML

#### Replace default javascript tag by importmap

```ruby






<%= current_page.data.title || "Middleman" %>
<%= stylesheet_link_tag "site" %>
<%= javascript_importmap_tags %>


<%= yield %>

```

#### Customize options if necessary

##### in `config.rb`:

```ruby
activate :importmap do |option|
option.entrypoint = "site" # js entrypoint's filename without extension
option.importmap = "importmap.yml" # importmap's filename with extension (yaml or json)
option.use_shim = true # or false
option.shim_src = "path/to/shim" # defaults to hardcoded js cdn
end
```

##### or by specifying arguments in template helpers:

This will override options in config.rb

```ruby
<%= javascript_importmap_tags("main", importmap: "importmap.json", shim: false) %>

# or customize one by one:
<%= javascript_importmap_shim_tag(shim_src: "another/path") %>
<%= javascript_inline_importmap_tag("importmap.json", shim: true) %>
<%= javascript_inline_module_tag("main", shim: true) %>

# See source code for methods implementation
```

## Examples
- [Creating an app using Stimulus JS](#creating-an-app-using-stimulus-js)
- [Creating an app using React and React Router](#creating-an-app-using-react-and-react-router)

### Creating an app using Stimulus JS

#### Add the following code to `/source/javascripts/site.js`

```javascript
import { Application } from "@hotwired/stimulus"

import HelloController from "./controllers/hello_controller.js"

window.Stimulus = Application.start()
Stimulus.register("hello", HelloController)
```

#### Create `controllers` directory

```shell
$ mkdir -p source/javascripts/controllers
```

#### Now add HelloController at `controllers/hello_controller.js`

```javascript
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
connect() {
console.log("Hello, Stimulus!", this.element)
}

greet() {
console.log("Clicked Greet Button")
}
}
```

#### One last and important thing is add element binding at `index.html.erb`

```ruby
---
title: Welcome to Middleman
---


Middleman is Running



Greet

<%= link_to(
"Read Documentation",
"https://middlemanapp.com/basics/templating_language/",
target: "_blank"
) %>
```

If all things are OK, than start middleman server using command `bundle exec middleman server` and open your browser devtools to see the messages.

### Creating an app using React and React Router

This example is based on [DHH's Youtube video presenting rails-importmap gem using React and htm](https://www.youtube.com/watch?v=k73LKxim6tw).

#### Change `importmap.yml` file to be like this

```yaml
---
imports:
"htm": "https://ga.jspm.io/npm:[email protected]/dist/htm.module.js"
"react": "https://ga.jspm.io/npm:[email protected]/index.js"
"react-dom": "https://ga.jspm.io/npm:[email protected]/index.js"
"react-router-dom": "https://ga.jspm.io/npm:[email protected]/dist/main.js"
"htm_create_element": "/javascripts/htm_create_element.js"

scopes:
"https://ga.jspm.io/":
"@remix-run/router": "https://ga.jspm.io/npm:@remix-run/[email protected]/dist/router.js"
"react-router": "https://ga.jspm.io/npm:[email protected]/dist/main.js"
"scheduler": "https://ga.jspm.io/npm:[email protected]/index.js"
```

#### Create `source/javascripts/htm_create_element.js` file

This file is necessary to use htm with React in an environment that doesn't have build process of JSX files.

```javascript
import { createElement } from 'react'
import htm from 'htm'

export const h = htm.bind(createElement)
```

#### Create `components` and `pages` directories

```shell
mkdir -p source/javascripts/components && mkdir -p source/javascripts/pages
```

#### Create `components/Page.js` file

Creating this file to avoid code duplication of components and demonstrate how to use composition in this environment.

```javascript
import { h } from "htm_create_element"

const Footer = () => h`



`

const Container = ({ children }) => h`


${children}

<${Footer} />
`

const Title = ({ children }) => h`

${children}


`

const Lead = ({ children }) => h`

${children}


`

export default {
Container,
Title,
Lead
}
```

#### Create `pages/Home.js` file

Now, let's create the Home page using the components created above and react-router-dom `Link` component.

```javascript
import { h } from "htm_create_element"
import { Link } from "react-router-dom"

import Page from "../components/Page.js"

export default () => h`
<${Page.Container}>
<${Page.Title}>Middleman Importmap React/>
<${Page.Lead}>
This is a simple page created using Middleman-importmap and React to demonstrate how it is possible to build
frontends in Middleman using importmap without any build.
/>





<${Link}
to="/getting-started"
class="btn btn-dark btn-lg"
role="button"
>
Getting Started
/>

GitHub
/>


/>
`
```

#### Create `pages/About.js` file

Creating just another page to demonstrate how to use react-router-dom `Link` behaviour.

```javascript
import { h } from "htm_create_element"
import { Link } from "react-router-dom"

import Page from "../components/Page.js"

export default () => h`
<${Page.Container}>
<${Page.Title}>About/>
<${Page.Lead}>
This is a simple About page
/>





<${Link}
to="/"
class="btn btn-dark btn-lg"
role="button"
>
Back
/>


/>
```

#### Create `components/App.js` file

Creating a component to wrap all pages and use react-router-dom `RouterProvider` component.

```javascript
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { h } from 'htm_create_element'

import Home from "../pages/Home.js"
import About from "../pages/About.js"

const router = createBrowserRouter([
{ path: '/', element: h`<${Home} />` },
{ path: '/about', element: h`<${About} />` }
])

export default () => h`<${RouterProvider} router=${router} />`
```

#### Add the following code to `site.js`

```javascript
import { render } from 'react-dom'
import { h } from 'htm_create_element'

import App from "./components/App.js"

const root = document.getElementById('root')
render(h`<${App} />`, root)
```

#### Add the following code to `source/index.html.erb`

```ruby
---
title: Welcome to Middleman
---

```

If all things are OK, than start middleman server using command `bundle exec middleman server`, open your browser and
access [http://127.0.0.1:4567/](http://127.0.0.1:4567/).

## See more

- [Importmap polyfill at guybedford/es-module-shims](https://github.com/guybedford/es-module-shims)
- [Can I Use about Import Maps browser support](https://caniuse.com/import-maps)
- [W3C Import Maps Spec](https://wicg.github.io/import-maps/)
- [The helper tags are inspired by rails/importmap-rails gem](https://github.com/rails/importmap-rails)

## License

See `./LICENSE` file for more details.

## Author

Daniel Vinciguerra