最近用 Rails7 + hotwire + importmap 的技术站做了个 AI 站,下图中标黄的都是有较多异步交互的地方,项目中基本没有使用手动 Ajax 与 JSON 交互,仅使用 turbo_frame、turbo_stream 来完成交互。
这里重点说说最新的 importmap 的使用问题,也欢迎大家体验下 kittyai.cn
下面是我的 config/imortmap.rb 部分内容,前面部分是脚手架生成的 hotwire 等库的配置。
这里 controller 目录里的文件是可以动态加载的,例如 HTML 中有某个 data-controller="message",才会加载 message_controller.js 文件。
额外引入了 highlight.js 的高亮配置,注意 importmap 是可以配置目录的。这里也发挥了其按需加载的优势,用到什么语言才加载什么语言的高亮代码。
# Pin npm packages by running ./bin/importmap
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "https://ga.jspm.io/npm:@hotwired/[email protected]/dist/stimulus.js"
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin_all_from "app/javascript/utils", under: "utils"
# For markdown preview
# https://jspm-packages.deno.dev/package/[email protected]
pin "markdown-it", to: "https://ga.jspm.io/npm:[email protected]/dist/markdown-it.js"
# For code syntax highlight
# 这里使用了路径 import https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap
pin "highlight.js/", to: "https://ga.jspm.io/npm:[email protected]/"
另外注意需要开启 HTTP2,能提升多文件加载的效率,例如在 Nginx 要这样配置:
server {
listen 443 ssl http2
}
除了可以通过静态的 import 来加载依赖,代码中甚至可以动态 import(),例如
import('highlight.js/lib/languages/' + language + ".js").then((module) => {
hljs.registerLanguage(language, module.default)
hljs.highlightElement(codeElement)
}).catch(err => {
console.warn("highlight error", err)
})
Javascript 的库一般会说用 npm install 等来安装,会依赖 window.process 里的环境变量,所以直接在 Web 端引入会报错。
例如 tippy.js 这个库,我是在 HTML 中加了下面的代码来 Fix:
<script type="application/javascript">
// Fix tippy ESM bug. https://github.com/atomiks/tippyjs/issues/990
window.process = { env: { NODE_ENV: 'production' }}
</script>
虽然 JS 可以通过 import 来动态还需加载了,写得很顺滑,但 CSS 并不会。
还是 tippy.js 的例子,需要在 HTML 中额外配置 CSS 依赖
<link rel="stylesheet" href="https://ga.jspm.io/npm:[email protected]/dist/tippy.css">
所以要不要用 importmap 还是需要谨慎。它的优势是细粒度、动态的加载 JS,但其普及度还不是很高,所以容易遇到细节问题。如果要考虑低版本浏览器,importmap 的加载性能和引入的代码的兼容性都可能是问题。