🗺️

Rails7 の importmap で npm package を使ってみる

2022/01/08に公開

importmap を採用した Rails で npm package を使う手順のメモです。

今回は typewriterjs というライブラリを入れてみます。

shell
$ ./bin/importmap pin typewriter-effect

Pinning "typewriter-effect" to https://ga.jspm.io/npm:typewriter-effect@2.18.2/dist/react.js
Pinning "object-assign" to https://ga.jspm.io/npm:object-assign@4.1.1/index.js
Pinning "process" to https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.14/nodelibs/browser/process-production.js
Pinning "react" to https://ga.jspm.io/npm:react@17.0.2/index.js

コマンドを叩くと config/importmap.rb に内容が反映されます。

config/importmap.rb
# 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: 'stimulus.min.js', preload: true
pin '@hotwired/stimulus-loading', to: 'stimulus-loading.js', preload: true
pin_all_from 'app/javascript/controllers', under: 'controllers'

# typewriter-effect
pin 'typewriter-effect', to: 'https://ga.jspm.io/npm:typewriter-effect@2.18.2/dist/react.js'
pin 'object-assign', to: 'https://ga.jspm.io/npm:object-assign@4.1.1/index.js'
pin 'process', to: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.14/nodelibs/browser/process-production.js'
pin 'react', to: 'https://ga.jspm.io/npm:react@17.0.2/index.js'

余談: react は使わないので書き換えました

config/importmap.rb
# 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: 'stimulus.min.js', preload: true
pin '@hotwired/stimulus-loading', to: 'stimulus-loading.js', preload: true
pin_all_from 'app/javascript/controllers', under: 'controllers'

# typewriter-effect
pin 'typewriter-effect', to: 'https://ga.jspm.io/npm:typewriter-effect@2.18.2/dist/core.js'
pin 'object-assign', to: 'https://ga.jspm.io/npm:object-assign@4.1.1/index.js'
pin 'process', to: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.14/nodelibs/browser/process-production.js'

stimulus の js ファイルに追記

home_controller.js
import { Controller } from "@hotwired/stimulus"
import Typewriter from "typewriter-effect"

export default class extends Controller {
  static targets = ["typewriter"]

  connect() {
    let target = this.typewriterTarget;
    if (target) {
      let customNodeCreator = (character) => {
        // Add character to input placeholder
        target.placeholder = target.placeholder + character;

        // Return null to skip internal adding of dom node
        return null;
      }

      let onRemoveNode = () => {
        if (target.placeholder) {
          // Remove last character from input placeholder
          target.placeholder = target.placeholder.slice(0, -1)
        }
      }

      new Typewriter(null, {
        strings: ['Hello', 'World'],
        autoStart: true,
        loop: true,
        delay: 75,
        onCreateTextNode: customNodeCreator,
        onRemoveNode: onRemoveNode,
      });
    }
  }
}

HTML に対応する記述をする。

<div data-controller="home">
  <div data-home-target="typewriter"></div>
</div>

動作確認

いい感じですね。

importmap-rails を使うことで、 Webpack, yarn, npm などのツールチェーンの一部を必要とせずに、ブラウザから直接 Javascript モジュールをインポートすることができます。

生成された importmap は以下。

<script type="importmap" data-turbo-track="reload">{
  "imports": {
    "application": "/assets/application-0038aad79cfa37268282d1d61a7147f29a757d59b7c79e1479f01f7ce16ce9aa.js",
    "@hotwired/turbo-rails": "/assets/turbo.min-305f0d205866ac9fc3667580728220ae0c3b499e5f15df7c4daaeee4d03b5ac1.js",
    "@hotwired/stimulus": "/assets/stimulus.min-900648768bd96f3faeba359cf33c1bd01ca424ca4d2d05f36a5d8345112ae93c.js",
    "@hotwired/stimulus-loading": "/assets/stimulus-loading-685d40a0b68f785d3cdbab1c0f3575320497462e335c4a63b8de40a355d883c0.js",
    "typewriter-effect": "https://ga.jspm.io/npm:typewriter-effect@2.18.2/dist/core.js",
    "object-assign": "https://ga.jspm.io/npm:object-assign@4.1.1/index.js",
    "process": "https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.14/nodelibs/browser/process-production.js",
    "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
    "controllers": "/assets/controllers/index-2db729dddcc5b979110e98de4b6720f83f91a123172e87281d5a58410fc43806.js",
    "controllers/root_header_controller": "/assets/controllers/home_controller-98ecd9c0511b83ff28a337338c5276d34662561fc5e22011b8b81d26a975594a.js"
  }
}</script>

参考

本記事は DHH が動画で紹介していた手順を参考にしたものです。

https://www.youtube.com/watch?v=mpWFrUwAN88&t=687s

Discussion