Importmap extension port for Middleman
MIT License
An Importmap extension for Middleman.
Add gem to Gemfile
gem 'middleman-importmap'
config.rb
**activate :importmap
importmap.yml
file at middleman root path$ cd middleman_project && touch importmap.yml
imports:
"@hotwired/stimulus": https://unpkg.com/@hotwired/stimulus/dist/stimulus.js
The importmap.yml file keep the same structure of importmap in HTML
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Use the title from a page's frontmatter if it has one -->
<title><%= current_page.data.title || "Middleman" %></title>
<%= stylesheet_link_tag "site" %>
<%= javascript_importmap_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
config.rb
: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
This will override options in config.rb
<%= 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
/source/javascripts/site.js
import { Application } from "@hotwired/stimulus"
import HelloController from "./controllers/hello_controller.js"
window.Stimulus = Application.start()
Stimulus.register("hello", HelloController)
controllers
directory$ mkdir -p source/javascripts/controllers
controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
console.log("Hello, Stimulus!", this.element)
}
greet() {
console.log("Clicked Greet Button")
}
}
index.html.erb
---
title: Welcome to Middleman
---
<h1>
Middleman is Running
</h1>
<div data-controller="hello">
<input type="text">
<button data-action="click->hello#greet">Greet</button>
</div>
<%= 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.
This example is based on DHH's Youtube video presenting rails-importmap gem using React and htm.
importmap.yml
file to be like this---
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"
source/javascripts/htm_create_element.js
fileThis file is necessary to use htm with React in an environment that doesn't have build process of JSX files.
import { createElement } from 'react'
import htm from 'htm'
export const h = htm.bind(createElement)
components
and pages
directoriesmkdir -p source/javascripts/components && mkdir -p source/javascripts/pages
components/Page.js
fileCreating this file to avoid code duplication of components and demonstrate how to use composition in this environment.
import { h } from "htm_create_element"
const Footer = () => h`
<footer class="footer mt-auto py-3 bg-body-tertiary">
<div class="container">
<span class="text-body-secondary">
Build by <a href="https://github.com/dvinciguerra">dvinciguerra<//> using <a href="https://github.com/dvinciguerra/middleman-importmap">middleman-importmap<//>.
</span>
</div>
</footer>
`
const Container = ({ children }) => h`
<main class="flex-shrink-0">
<div class="container">
${children}
</div>
</main>
<${Footer} />
`
const Title = ({ children }) => h`
<h1 class="mt-5">${children}</h1>
`
const Lead = ({ children }) => h`
<p class="lead">${children}</p>
`
export default {
Container,
Title,
Lead
}
pages/Home.js
fileNow, let's create the Home page using the components created above and react-router-dom Link
component.
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.
<//>
<hr class="my-4" />
<p>
<${Link}
to="/getting-started"
class="btn btn-dark btn-lg"
role="button"
>
Getting Started
<//>
<a
href="https://github.com/dvinciguerra/middleman-importmap"
class="btn btn-secondary btn-lg ms-1"
role="button"
target="_new"
>
GitHub
<//>
</p>
<//>
`
pages/About.js
fileCreating just another page to demonstrate how to use react-router-dom Link
behaviour.
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
<//>
<hr class="my-4" />
<p>
<${Link}
to="/"
class="btn btn-dark btn-lg"
role="button"
>
Back
<//>
</p>
<//>
components/App.js
fileCreating a component to wrap all pages and use react-router-dom RouterProvider
component.
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} />`
site.js
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)
source/index.html.erb
---
title: Welcome to Middleman
---
<div id="root"></div>
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/.
See ./LICENSE
file for more details.
Daniel Vinciguerra