記法がたくさんあって難しいので調べた。
モジュール化とは
モジュール化とは、別ファイルに分割することである。
require.jsとは
require.jsとは、モジュール化するためのライブラリである。
requireとは
requireとは、「必要とする」という意味の動詞。
やってみた
以前やってみたが、じつは他にも記法がたくさんある。
require.jsの使い方
公式サイトのAPIリファレンスを参照した。これを読めばマスターできるが、多すぎるので以下に抜粋する。
これさえあればいい
こんなときどう書く?
プラグイン
- 6.テキストファイル受信
- 7.DOM読込完了待機
- 8.国際化(i18n)
コード
構成
- index.html
- js/
- app.js
- lib/
- require/
- require.js
- require/
- app/
- main.js
- sub.js
main.jsからsub.jsを呼び出すのが狙い。
ファイル内容
index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script data-main="app.js" src="js/lib/require/require.js"></script> </head> <body></body> </html>
app.js
require(['js/app/main.js']);
main.js
define(function(require, exports, module) { var sub = require('js/app/sub'); sub.print("MESSAGE!!"); });
sub.js
define(function() { return { print: function(msg) { alert(msg); console.log(msg); } }; });
index.html
data-main
属性によりエントリポイントを指定している。
index.html
<script data-main="app.js" src="js/lib/require/require.js"></script>
特殊な記法だが、ほかにもいくつかパターンがある。この方法が最もスマート。
app.js
requireの設定をするときにmain.jsと分離しておきたいから用意した。たとえば以下のように分離する。
app.js
require.config({ paths: { jquery: "js/lib/jquery/jquery-3.3.1.min.js" } }); require(['js/app/main.js']);
main.js
define(function(require, exports, module) { var $ = require('jquery'); $("body").html("Hello jQuery !!"); });
main.js
CommonJS方式。
define(function(require, exports, module) {
引数exports
, module
は使っていないので省略できる。
define(function(require) {
sub.js
define(function() {
もし他のコードをインポートしたくなったらrequire
引数を追加する。
define(function(require) { var $ = require('jquery');
exports
, module
を追加してもいい。
define(function(require, exports, module) {
ES6 class
ES6のclassが実装されてるなら使うといい。
main.js
define(function(require, exports, module) { const Human = require('js/app/Human'); const h = new Human("Yamada"); h.Speak(); });
Human.js
define(function() { return class Human { constructor(name=null){ this._name = name; } get Name() { return this._name; } set Name(v) { if(v){ this._name = v; } } Speak() { alert(this._name); console.log(this._name); } }; });
sub.jsをHuman.jsに置き換えた。class
をreturn
している。
モジュール化
require.jsでモジュール化するコードの記法は場合によってたくさんある。以下のうち1.3.5 Define a Module with Simplified CommonJS Wrapperの方法が最も汎用的だと思う。
コード概要 | 説明URL |
---|---|
require(){...} |
1.2 data-main Entry Point |
define({...}) |
1.3.1 Simple Name/Value Pairs |
define(function () {... return {...};}) |
1.3.2 Definition Functions |
define(["./foo", "./bar"], function(foo, bar) {... return {...};}) |
1.3.3 Definition Functions with Dependencies |
define(["./foo", "./bar"], function(foo, bar) {... return function(){...};}) |
1.3.4 Define a Module as a Function |
define(function(require, exports, module) {... return {...};}) |
1.3.5 Define a Module with Simplified CommonJS Wrapper |
define("foo/title", ["a/A", "a/B"], function(A, B) {...}); |
1.3.6 Define a Module with a Name |
define(["require", "./relative/name"], function(require) { var mod = require("./relative/name"); }); |
1.3.7 Other Module Notes |
define(function(require) { var mod = require("./relative/name"); }); |
1.3.7 Other Module Notes Better |
define(["require", "a"], function(require, a) { return function(title) { return require("a").doSomething(); }}); or define(function(require, exports, module) { var a = require("a"); exports.foo = function () { return a.bar(); }; }); |
1.3.8 Circular Dependencies 循環参照 |
require(["http://example.com/api/data.json?callback=define"], function (data) { console.log(data); }); |
1.3.9 Specify a JSONP Service Dependency |
比較
以下のうちAのほうが好ましい。特にインポートするファイル数が多くなると顕著。
インポート数1
A
define(function (require) { var sub = require('js/app/sub'); return function () { sub.print(); }; });
B
define(['js/app/sub'] , function (sub) { return function () { sub.print(); }; });
インポート数3
A
define(function (require) { var sub1 = require('js/app/sub1'); var sub2 = require('js/app/sub2'); var sub3 = require('js/app/sub3'); return function () { sub1.print(); }; });
インポートの追加や削除をするとき、行の編集だけで済む。
B
define(['js/app/sub1','js/app/sub2','js/app/sub3'] , function (sub1,sub2,sub3) { return function () { sub1.print(); }; });
インポートの追加と削除をするとき、配列と引数をそれぞれ編集せねばならない。カンマの編集や、配列と引数の位置を合わせねばならない。ミスしそう。可読性が低い。
循環参照
A, Bともに少し特殊な記述になる。
A
js/app/sub2.js
define(function(require, exports, module) { var sub1 = require("js/app/sub1"); exports.foo = function () { return sub1.print(); // sub1.jsで本ファイルsub2.jsを参照する }; });
sub2.jsでエクスポートしたい場合、exports
オブジェクトに生成する必要がある。(非循環参照の場合:エクスポートするオブジェクトはreturn
で返していた)
B
js/app/sub2.js
define(['js/lib/require/require', 'js/app/sub1'] , function (require, sub1) { return function() { return require("js/app/sub1").print(); // sub1.jsで本ファイルsub2.jsを参照する } });
require.js
をインポートする必要がある。(非循環参照の場合:require.js
のインポートは不要だった)