项目中使用 Rails7 importmap 的体验

99 阅读2分钟

前言

最近用Rails7 + hotwire + importmap 的技术站做了个AI站,下图中标黄的都是有较多异步交互的地方,项目中基本没有使用手动 Ajax 与 JSON 交互,仅使用 turbo_frame、turbo_stream 来完成交互。

这里重点说说最新的 importmap 的使用问题,也欢迎大家体验下 kittyai.cn

Importmap 的基本用法

  1. importmap.rb 示例

下面是我的 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/stimulus@3.2.1/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/markdown-it@13.0.1
pin "markdown-it", to: "https://ga.jspm.io/npm:markdown-it@13.0.1/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:highlight.js@11.9.0/"
  1. 开启HTTPS

另外注意需要开启HTTP2,能提升多文件加载的效率,例如在Nginx要这样配置:

server {
  listen 443 ssl http2
}
  1. 逻辑动态import

除了可以通过静态的 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)
})

遇到的问题

  1. 有些库对ES Module支持得不好

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>
  1. Importmap 不会管理 CSS

虽然JS可以通过 import 来动态还需加载了,写得很顺滑,但CSS并不会。

还是 tippy.js 的例子,需要在HTML中额外配置CSS依赖

<link rel="stylesheet" href="https://ga.jspm.io/npm:tippy.js@6.3.6/dist/tippy.css">

总结

所以要不要用 importmap 还是需要谨慎。它的优势是细粒度、动态的加载JS,但其普及度还不是很高,所以容易遇到细节问题。如果要考虑低版本浏览器,importmap的加载性能和引入的代码的兼容性都可能是问题。