Javascriptのファイル読み込み構成ベストプラクティス

2022年3月5日

Javascript テクノロジー

eyecatch Javascriptを制するものは、インターネットブラウザを制す! この言葉を信じる、ユゲタです。 え?誰の言葉ですかって? 誰も言ってません。ユゲタが言っているだけです。 でもあながちウソではないと思いませんか? だって、インターネットブラウザって、パソコンがあれば必ず誰もが使っているし、 最近では、IoT機器や家電製品などの表示として、WebView的なモノが使われていたり、 家庭用テレビゲーム端末なんかは、インターネットブラウザが見られるようになっていますからね。 そう考えると、インターネットブラウザは世界で一番数多く使われているインターネット描画プラットフォームであると言えます。 その中で、唯一プログラミングできる領域は、Javascriptだけなんですよ。 これまで、そのJavascriptを使って、いろいろなインターネットサービスを生み出してきた、ユゲタとしては、モジュール構成なども含めて、 どーいう構成が望ましいのか? 古い書き方で、安定した書き方をした方がいいのか? 新しめの書き方で、最先端の構築をした方がいいのか? そうした初心者が入りにくいJavascriptのファイル構成についてブログに備忘録しておきたいと思います。 ちなみに、今回のテーマは「効率的な外部Javascriptファイルの読み込み方」です。

ブラウザのメモリキャッシュに直接読み込む最もシンプルで未対応ブラウザが無い書き方

# HTMLに直接読み込む

<script type="type/javascript" src="library.js"></script> 最もスタンダードで、HTMLをコーディングする人なら誰でも一度は打ち込んだ安定した読み込み方です。 基本的にホームページにJavascriptを読み込む場合は、必ずこの記述をする必要があるので、必要最低限方法になります。

# Javascriptファイルから別のJavascriptを読み込む

const script = document.createElement("script"); script.type = "text/javascript"; script.src = "load.js"; script.onload = function(){ // load.jsを読み込み完了した時の処理 } document.body.appendChild(script); これも、どんなに古いインターネットブラウザでも安定して動作する事ができる書き方で、一番上位階層のJavascriptが別のJavascriptを読み込む方法として記述します。 ちなみに、type="text/javascript"は、HTML5からは、記述しなくても良くなったんですが、古めのブラウザでは、必要な場合もあるので、要点を理解して削除して使ってください。

# nodejs環境での読み込み

const load = require("load.js"); // loadが実行関数の場合 load(); この書き方は、Nodejsで使う用です。 通常のHTML+Javascriptの構成では使えないので、少し番外編ですが、Reactなど、Nodejsベースのフレームワークを使う時には必須ですね。

# import/export

<!DOCTYPE html> <html> <head> <meta charset ="utf-8"> <title>import</title> <script type="module" src="load.js"></script> </head> <body> <h1>import</h1> <div id="content"></div> </body> </html> 'use strict' import * as SUB from './sub.js' SUB.write("test"); export function write(){ document.getElementById("load").innerHTML = "loaded"; } IEを含めた古めのブラウザでは機能しませんが、今の所一番構成を組みやすいのは、このimport/export方式ではないでしょうか? ファイルごとにライブラリを読み込む書き方は、C言語のincludeと同じ感じですね。 これまでJavascriptを使ってきた人は、ちょっと戸惑うかもしれませんが、Classやその継承などの処理も書けるので、大きめのプログラムを書くときも非常に効率的に構築できます。

# インターネットブラウザを効率的に使う方法

そして、上記のimport/exportの問題点の一つは、読み込み時間のコントロールがしずらいという点ですね。 大きいなプログラムを細切れにして、たくさんのファイル構成をimportしようとすると、効率的なんですが、無駄なリクエストヘッダのパケットが発生してしまいます。 これまでのjavascript読み込みの方法だと、サーバーサイドで、複数のjavascriptを1つにまとめて、1つのリクエストとして扱う事ができるのですが、importする場合は、ファイル単位で、変数などの扱いも重要になります。 もちろんそれを加味して構成を作ってもいいのですが、ちょっと裏技的な方法を考えてみました。 一度、javascriptのメモリにファイルを読み込み、それをキャッシュします(この時に、MB単位でなければ、localstorageにキャッシュしておいてもいいかもですね)。 キャッシュされた文字列のjsプログラムをimport実行させる方法です。 <!DOCTYPE html> <html> <head> <meta charset ="utf-8"> <title>Require</title> <script type="module" src="import_cache.js"></script> </head> <body> <h1>javascript import</h1> <div id="import"></div> </body> </html> const settings = { query : {}, // Array , Object each ok ( ex: {a:"1"} or ["a=1"] ) methid : "post", // post | get async : true, content : "application/x-www-form-urlencoded", // content-type success : function(data , options , req , res){}, error : function(data , options , req , res){}, type : "", // request-type header : "", // request-header } /** * Ajax tool * sample : * import { Ajax } from "./ajax.js" * new Ajax({ * url : "http://example.com", * query : { * a : "a" * }, * success : function(response , request){ * ... * }, * error : function(err){ * ... * } * }); */ export class Ajax{ constructor(options){ if(!options){ return } this.options = this.setOptions(options) if(!this.options.url){ return } this.setQueries() this.flow() } setOptions(options){ for(var i in settings){ options[i] = (typeof options[i] === "undefined") ? settings[i] : options[i] } return options } setQueries(){ if(!this.options || !this.options.query || typeof this.options.query !== "object"){return} this.queries = []; if(this.options.query.constructor === Array){ for(let q of this.options.query){ var sp = q.split("="); this.queries.push(sp[0]+"="+encodeURIComponent(sp.slice(1))); } } else{ for(var i in this.options.query){ this.queries.push(i+"="+encodeURIComponent(this.options.query[i])); } } } createHttpRequest = function(){ if(window.ActiveXObject){ //Win ie用 try{ return new ActiveXObject("Msxml2.XMLHTTP") //MSXML2以降用; } catch(e){ try{ return new ActiveXObject("Microsoft.XMLHTTP") //旧MSXML用; } catch(e2){return null} } } else if(window.XMLHttpRequest){ return new XMLHttpRequest() //Win ie以外のXMLHttpRequestオブジェクト実装ブラウザ用; } else{return null} } flow(){ this.req = this.createHttpRequest() if(!this.req){return} this.open() this.content() this.req.onreadystatechange = this.readyState.bind(this) this.type() this.send(); } open(){ this.req.open(this.options.method , this.options.url , this.options.async); } content(){ if(!this.options.content){return} this.req.setRequestHeader('Content-Type', this.options.content); } type(){ if(!this.options.type){return} this.req.responseType = this.option.type; } send(){ const queries = (!this.queries.length) ? this.queries.join("&") : null; this.req.send(queries); } readyState(res){ if (this.req.readyState==4){ //コールバック if (this.req.status === 200) { this.options.success(this.req.responseText , this.options , this.req , res); } else{ this.options.error(this.req.responseText , this.options , this.req , res); } } } } import { Ajax } from "./ajax_import.js"; new Ajax({ url:"import_cache_sub.js", method : "get", success : async function(data){ const src = "data:text/javascript;base64," + btoa(data); const func = await import(src); func.loaded("test"); } }); export function loaded(){ document.getElementById("import").innerHTML = "Loaded"; } ajax_cache.jsは、ユゲタが独自で利用しやすいように作ったajaxライブラリです。 別の方法でもいいので、とにかく、jsファイルを文字列でゲットする事ができれば、import処理をするのは、比較的簡単なんですね。 一つ注意点は、async - awaitは必須なので、これで処理完了するようにしないといけないようです。

まとめ

Javascriptは、非常に更新の早い言語で、Javascriptからの派生言語もたくさん出てきています。 学習コストはかなり高くなっているものの、使えるとたくさんのできる幅が広がる言語でもあるので、覚えて損はないプログラム言語であると言えます。 仕事でも、プライベートでも、javascriptプログラミングで構成を構築できるよおうになると、きっと楽しいインターネットブラウザライフが待っていると思いますよ。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ