つまずきニュースレター(2024-05-24号)
はじめに
ファンタラクティブのエンジニアチームはMob.*(モブアスタリスク)という取り組みを毎週行っており、それぞれのメンバーがどのような開発に取り組んでいるか・業務でつまずいたことを社内で共有しています。
このニュースレターでは、その中でも実際の業務で起きたつまずきをピックアップし、まとめています。
Lenis ライブラリを Nuxt に導入した際に、ES module をサポートしていないというエラーへの対応
プロジェクトで慣性スクロールを実現するために、Lenisという JavaScript ライブラリを Nuxt フレームワークで使用することにしました。以下はサンプルコード (Nuxt.js v2 x TypeScript)になります。
<script lang="ts">
import Vue from 'vue'
import Lenis from 'lenis'
const lenis = new Lenis()
export default Vue.extend({
mounted() {
function raf(time: number) {
lenis.raf(time)
requestAnimationFrame(raf)
}
requestAnimationFrame(raf)
},
})
</script>
ですが、このライブラリを導入した際に、Nuxt が ES module をサポートしていないというエラーが発生しました。
require() of ES Module /Users/xxx/Documents/sandbox/test-nuxt-app-2/node_modules/lenis/dist/lenis.mjs not supported. Instead change the require of /Users/xxx/Documents/sandbox/test-nuxt-app-2/node_modules/lenis/dist/lenis.mjs to a dynamic import() which is available in all CommonJS modules.
原因
Nuxt のビルドシステムは、ES module をサポートしていないライブラリに対しては、動的インポートを使用する必要があるという制約があります。
この制約に対応するため、いくつかの対策が必要となりました。
対応
具体的な対応策として、まず**nuxt.config.ts
**のビルド設定において、Lenis ライブラリをトランスパイルする処理を追加しました。これにより、ライブラリが Nuxt のビルドプロセスに適合する形で処理されるようになります。
export default {
...
build: {
extend(config) {
// Lenisライブラリをトランスパイル
config.module?.rules.push({
test: /\/node_modules\/lenis\//,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
})
}
}
}
さらに、プラグインファイル内で Lenis を動的にインポートする方法を採用しました。const lenis = new Lenis()
のように、静的インポートした Lenis をインスタンス作成する宣言があると先のエラーになります。
<script lang="ts">
import Vue from 'vue'
import Lenis from 'lenis'
export default Vue.extend({
data(): { lenis: Lenis | undefined } {
return {
lenis: undefined
}
},
mounted() {
import("lenis").then((lenis) => {
const lenisInstance = new (lenis.default || lenis)()
this.lenis = lenisInstance
const raf = (time: number) => {
this.lenis?.raf(time)
requestAnimationFrame(raf)
}
requestAnimationFrame(raf)
})
},
})
</script>
参考
タッチデバイスを判別しようとしたとき、iPad が MacOS と誤判定されてしまう問題
タッチイベントとポインタイベントの処理をデバイスごとに区分する際、iPad をタッチ対応デバイスとして正しく判別する必要がありました。
ですが、開発中に iPad が MacOS と誤判定される問題が発生しました。
原因
この誤判定の原因は、iPad 上のブラウザがユーザーエージェントで「Mac OS」と表示しているためです。
特に、iPad の Chrome では「Mac OS」ではなく「iPad」と正しく表示されるのですが、Safari など他のブラウザではこのような現象が見られました。
対応
この問題に対応するために、ユーザーエージェントの文字列に「Mac OS」と含まれているかを確認し、さらにdocument.ontouchstart
が undefined ではないかをチェックすることで、タッチ機能が実際に存在するかどうかを確認する方法を取り入れました。
この判定方法は、以下のコードブロックに示すように実装できます。
const isTouchCapable =
/Mac OS/.test(navigator.userAgent) && document.ontouchstart !== undefined;
このコードにより、ユーザーエージェントでは「Mac OS」と表示されるもののタッチ機能を持つデバイス、つまり iPad であることを正確に判定できるようになりました。
参考
Windows の Excel で CSV ファイルを開くと日本語が文字化けする
背景
Web 上からダウンロードした CSV を Windows の Excel 上で開くと、文字化けが発生していました。
原因
どうやら Windows の Excel で CSV ファイルを開くと、デフォルトで Shift-JIS で読み込まれてしまうようでした。今回使用していた CSV ファイルは文字コードが UTF-8 のファイルだったため、Shift-JIS で読み込むと文字化けしてしまいうまく表示されませんでした。
対応
以下のコードのようにファイル内容の先頭に文字列を付与することでこれを回避することができます。
const BOM = "\uFEFF";
const csvData = BOM + csvContent;
追加する文字列は BOM ( byte order mark)と呼ばれ、そのファイルが Unicode で表現されたファイルであることを アプリケーション(Excel) に伝えることができます。
ちなみに差し込んだ BOM が Excel 上に表示されることはありません。
参考
画面外に出てしまう要素を画面内に収める
背景
下の画像のように、ユーザーが自由にドラッグできる要素にて画面外に要素を運んでしまった際に、再度操作できるよう画面内に戻す処理を実装していました。
今回は document.body のサイズを用いて判定を行なっていたのですが、うまくいかない場合がありました。
原因
スクロールが発生するページにおいて document.body のサイズが window のサイズよりも大きくなってしまい、画面外に移動できる状態となっていました。
対応
body の代わりに、位置を制御する window と同サイズのコンテナのような要素を作成し、それをもとに制御するようにしました。画面いっぱいに要素を広げるには以下のようなスタイリングで実現できます。
.container {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
上記 UI は Chrome の拡張機能として実装されています。拡張機能の開発では、plasmo というフレームワークを使っており通常の Web 開発と同じような感じで実装できています。ホットリロードが遅いなど難点もありますが、React も使えたりといい感じです。
おまけ 🍪
iPad がユーザーエージェントで MacOS と表示される問題について、具体的な対策としてdocument.ontouchstart
をチェックする方法は初知りでした。また、文字エンコーディングは何度もつまずいてきた人も多いかもしれませんね。参考になれば嬉しいです!
最後に
ファンタラクティブではフロントエンド・バックエンド問わず絶賛エンジニア募集中です!
気になる方は下のリンクをクリック!
![ファンタラクティブテックブログ](https://storage.googleapis.com/zenn-user-upload/avatar/b8bb6b6843.jpeg)
ユーザーファーストなサービスを伴に考えながらつくる、デザインとエンジニアリングの会社です。エンジニア積極採用中です!hrmos.co/pages/funteractive/jobs
Discussion