jQuery 1.8 から 3.4 まで順番にアップデートしていく
https://1.bp.blogspot.com/-AboWGB8f5Ig/XmG2uL-RbUI/AAAAAAABXvU/_o_UlxYUWqYw3r37sRiLc6ms4yJQTBvKwCNcBGAsYHQ/s400/nekonote_karitai_man.png
jQuery 1.8 から現時点での最新版 jQuery 3.4.1 まで順番にアップデートしていく方法をご紹介します。 お手元のエディタで以下のサンプルを index.html などで適当に配置してください。
これに含まれる JavaScript は IE11 で動作することを前提に最新の jQuery 3.4.1 では動作しないように設計されています。 また今回 IE11 で動作することを要件にしているので Arrow Function など Polyfill で解決できない書き方は避けています。
code:sample.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="app">
<div>
<h3>jQuery version:</h3>
<p>Version: <span id="jquery-info"></span></p>
</div>
<div>
<h3>Browser version:</h3>
<p>Version: <span id="browser-info"></span></p>
</div>
<div>
<h3>Checkbox test:</h3>
<input type="checkbox" name="platform" value="windows" id="platform-windows" /><label for="platform-windows">Windows</label>
<input type="checkbox" name="platform" value="macos" id="platform-macos" /><label for="platform-macos">macOS</label>
<input type="checkbox" name="platform" value="linux" id="platform-linux" /><label for="platform-linux">Linux</label>
<input type="submit" id="platform-submit" />
</div>
</div>
<script>
$(function () {
$('#jquery-info').text($.fn.jquery)
$('#browser-info').text($.browser.version)
$('#platform-submit').click(function () {
var platforms = []
platforms.push($(e).val())
})
if (platforms.length == 0) {
platforms.push('(empty)')
}
alert('Checked: ' + platforms.join(', '))
})
})
</script>
</body>
</html>
前提として必要な心構え
今回のプロセスにおいては以下のような方針のもと更新を行うこととします。
モダンブラウザ(死語?) で利用できない API については Polyfill を利用してカバーします。
jQuery Migrate Plugin とは
jQuery の旧バージョンからのアップデートをサポートするプラグインです。具体的には、新バージョンで廃止された動作を復元し、ブラウザの検証ツール上に使用された非互換機能のレポートを通知します。 (IE9 のような console.*** をサポートしない環境では Polyfill の適用が必要になります)
Migrate Plugin を使うことで、古い記載のまま新バージョンの jQuery を使うことができますが、基本的には移行のために用意された機構なので、時間を見つけて記載から更新するように頑張りましょう。
旧環境向けの Polyfill について
CDN から利用できる Polyfill には、メジャーどころで下記の 2つ が存在します。 機能については差は大きくありませんが、それぞれ特徴があります。
Babel Polyfill
npm で @babel/polyfill として配信されている Babel のサブプロジェクトの Polyfill です。
https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.7/polyfill.min.js
Polyfill.io
利用中のブラウザのバージョンを検知し、必要な最小限の Polyfill を配信するサービスです。
外部アセットのサイズを小さくしたいシーンにおいて便利に使えます。
https://polyfill.io/v3/polyfill.min.js を指定するとすべての Polyfill が環境に応じて配信されます。
必要に応じて使い分けると良いでしょう。今回は polyfill.io を利用することとします。
これにより後述する標準APIへの書き換えを気軽に行えるようにしています。
jQuery 1.8 から 1.12 へアップデート
最終的に 3.x にするには現状 1.8 で動いているコードを一旦 1.12.x までアップグレードする必要があります。
まずは 1.8 から 1.12 にアップグレードするためスクリプトの読み込みを 1.12 に切り替えます。
加えて 1.x-stable 版の jQuery Migrate Plugin を設定します。
code:diff
これにより 1.8 から 1.12 までの間で廃止された機能を利用しつつアップデートすることができました。
このとき廃止された機能を利用している場合、検証ツールにレポートが上がっています。
$.browser が 1.9 で廃止されているためこのような表記になっていますが処理自体は実行できている状態です。
https://gyazo.com/9162424f8b2da993d38f32b781a2453c
この機能の代替は modernizer などの別ライブラリを利用することが推奨されていますのでそういう形に改めておきましょう。
jQuery のバージョン更新に際してはこう言う、代替えライブラリの移行はしばしば発生します。jQuery が DOM の探索を簡略化するライブラリであるため、それに直接関係しない機能は徐々に削がれてサポートライブラリへと分離されていっています。
また、jQuery Plugin もバージョンが更新されたことで動かなくなるということは十分にありえるので、このタイミングで警告のもとになっているプラグインは削除や置き換えを行うと良いでしょう。
今回は面倒なので該当箇所は不要と判断して削除してしまうことにします。
削除ができたら jquery-migrate-1.4.1.js の読み込みは削除して正常に動作することを確認しておきましょう。
jQuery 1.12 から 3.4 へアップデート
最新の jQuery Migrate Plugin が対応可能な状態になったので、jQuery 1.12 を 3.4.1 に差し替え、対応する Migrate Plugin を読み込み有効にします。
code:diff
そして再びレポートを確認します。
https://gyazo.com/0ad66c6ec175016696992a433288ab27
今度は $('...').click がレポートされていました。
これは廃止された糖衣構文で $('...').on('click', () => { ... }) という形に改めておく必要がありますのでやっちゃいましょう。
変更後レポートがなくなったことを確認したら migration を削除しておきましょう。
標準APIへの書き換え
ここまでで サンプルにおける jQuery の最新化が完了しました。
もし余裕があれば jQuery を使わずとも対応できるものはパフォーマンスや今後の jQuery の非互換更新の追従にかかるコストを考えて標準API (Vanilla JS とも呼ばれる実装手法) への書き換えを行ってみても良いかもしれません。サンプル中にある記載で書き換えられるものはざっと下記に例示します。 変数定義は const もしくは let へ
変えるほうが無難です。少なくとも IE 11 までのサポートで済むなら var は let に機械的に変えて多くの場合は問題ないはず...
レビューや期間を開けたときコードを見直すときに再代入の有無を考えるのはそこそこ大変なので個人的には const をおすすめしたい。
code:js
// 再代入を伴わない場合は基本 const
const variable = 'something'
// 再代入をどうしても必要とする場合は let
let variable = 'something'
値の比較は === で
== で比較すると暗黙の型変換がかかります。型まで含んだ一致を確認するには === で比較するように改めましょう。
DOMの探索 - id を使う場合
getElementById を使います。id は document 中一意にきまるので結果は唯一のDOMになります。
code:diff
- $('#something').fn( ... )
+ document.getElementById('something').fn( ... )
DOMの探索 - CSS セレクタを使う場合
CSS セレクタを利用してDOMを取得する場合は querySelector もしくは querySelectorAll を利用します。
code:diff
jQuery.text は innerText へ
code:diff
- $('#jquery-info').text($.fn.jquery)
+ document.getElementById('jquery-info').innerText = $.fn.jquery
jQuery.on('click', ...) は addEventListener('click',...) へ
ちょっと長ったらしいですが、割とすぐ慣れますね。エディタに補完がないときは…(うん)
code:diff
- $('#platform-submit').on('click', function() { ... }
+ document.getElementById('platform-submit').addEventListener('click', function() { ... }
jQuery.each は NodeList.forEach へ
querySelectorAll と組み合わせて NodeList.forEach、もしくは for...in for...of を使用します。
map や some などの Array の関数を利用したい場合は Array.from を利用し Array へと変換しましょう。
求める結果が配列の場合は、forEach を使っておくと処理をチェインしやすくて便利ですね。
code:diff
- $('...').each(function () { ... })
+ document.querySelectorAll('...').forEach(function () { ... })
$(document).ready は必要がなければ即時関数の実行へ
jQuery を使う場合 $(document).ready(function{ ... }) もしくは $(function(){ ... }) と書くことでページの読み込み完了時にコールバック関数を実行するようにフックできます。読み込み完了で必ず実行する必要がなくグローバル領域を使わないようにする意図でこれらを使っていた場合は、即時関数の実行で代替え可能です。
逆にもし読み込み完了時に実行が必要であれば、window オブジェクトに対して addEventListener を利用して DOMContentLoaded に対してフックを設定すると良いでしょう。
結果発表
改めて移行前のスクリプトを見てみましょう。(※ 廃止してしまった browser は予め削除してあります。)
code:before.js
$(function () {
$('#jquery-info').text($.fn.jquery)
$('#platform-submit').click(function () {
var platforms = []
platforms.push($(e).val())
})
if (platforms.length == 0) {
platforms.push('(empty)')
}
alert('Checked: ' + platforms.join(', '))
})
})
続いて最終的に移行しきったコードがこちら。
code:after.js
(function () {
document.getElementById('jquery-info').innerText = 'vanillajs'
document.getElementById('platform-submit').addEventListener('click', function() {
const platforms = Array
.map(function (e) { return e.value })
if (platforms.length === 0) {
platforms.push('(empty)')
}
alert('Checked: ' + platforms.join(', '))
})
})()
jQuery は DOM の探索を簡単するためのライブラリなので、やはり短くかけることについては分がありますね。
「jQueryはやめないといけないもの」というわけでも無いので、余裕や必要に応じて良い選択をしていきましょう。