JavaScriptにも@importを
JavaScriptにも、CSSのような@importが欲しい。
ってとき、多くの場合はscriptタグ を document.write するんだけど、相対パスの基準ディレクトリが問題になる。CSSから他のファイルを参照するときは、そのCSSファイルのあるディレクトリが相対パスの基準になるけど、document.write じゃ HTMLのURLが基準になってしまう。そのせいで、scriptタグを document.write するスクリプト(import.jsとか)を、階層の異なるHTMLから共通して使うのがちょっと難しい。
普通の解法は、import.jsを使う前に、相対パスプレフィクスを変数に入れておくか、インポートを関数として、HTMLから基準パスを渡すか…。
<script type="text/javascript"> var GLOBAL_JAVASCRIPT_PREFIX = "../../js/"; </script> <!-- import.js が一括で scriptタグ を document.write する --> <script type="text/javascript" src="../../js/import.js"></script>
<script type="text/javascript" src="../../js/import.js"></script> <script type="text/javascript"> import_all("../../js/"); //ベースパスを渡す </script>
…どっちもDRYじゃないからダサいなぁ。
で、突如思いついたのがこの方法。
HTMLで、外部ファイルのスクリプトが実行される瞬間、「DOMの最後の要素」は scriptタグであり、src属性には「HTMLからみたスクリプト自身のパス」が書かれている。そいつを暗黙的にデフォルトとすれば…
(function() { var jsfiles = ["a.js", "b.js"]; // ロードされるスクリプト(このファイルからの相対パス指定) /****************************** DO NOT EDIT BELOW *****************************/ function lastof(es) { return es[es.length - 1]; } function dirname(path) { return path.substring(0, path.lastIndexOf('/')); } var prefix = dirname(lastof(document.getElementsByTagName('script')).src); for(var i = 0; i < jsfiles.length; i++) { document.write('<script type="text/javascript" src="' + prefix + '/' + jsfiles[i] + '"></script>'); } }).call(this);
これで、
<script type="text/javascript" src="../js/import.js"></script>
は
<script type="text/javascript" src="../js/a.js"></script> <script type="text/javascript" src="../js/b.js"></script>
だし、
<script type="text/javascript" src="../../js/import.js"></script>
は
<script type="text/javascript" src="../../js/a.js"></script> <script type="text/javascript" src="../../js/b.js"></script>
になる。
まあ、import.js の scriptタグをDOMの途中に挿入したらアウトだけど、そもそも、それだと document.write がアウトだから、気にしない気にしない。