◆ 早く使いたい

import とか export とか

複数ページの共通部分とか 綺麗に切り離したい いかにもモジュールっぽい部分とか ファイル分割したいことってあります
いまの仕組みだと HTML のほうに script タグを大量に書かないとだめなので module 使えるようになってほしいなぁと思います

いまのところ いろいろぐぐってみても chromium のほうでも実装されたとか聞かないですし そもそも他の ES6 とは別扱いされてる感があります
ES6 の compat table にも載っていないです
さらに 少し前に ES module は特殊で実装的に決まってないような事が多くてどうこう とか Node.js の require の仕様とのどうこうとか そんなのを聞いた気がするのでこれまでの ES6 が次々使えるようになってたようにはいかなそうです


でも module ごとにファイルロードしてグローバルにいろいろあるのも嫌なので module ぽいことをできるようにこんなのを準備してみました

[module.js]
Module = {
modules: {},
promises: {},
load(name, opt){
name = this._nameOptimize(name)
opt = opt || {}
var url = opt.url || name + ".js"
var max_wait = ~~max_wait
if(!(name in this.modules)){
var s = document.createElement("script")
s.async = false
s.src = url
document.head.appendChild(s)

var promise = this._createOpenPromise()
max_wait > 0 && setTimeout(reject, max_wait)
this.promises[name] = promise
}
return this.promises[name]
},
set(name, m){
name = this._nameOptimize(name)
if(name in this.modules){
return true
}else{
this.modules[name] = m
this.promises[name] && this.promises[name].resolve(m)
return false
}
},
get(name){
name = this._nameOptimize(name)
if(!(name in this.modules)) throw new Error(name + " is not loaded")
return this.modules[name]
},
getAsync(name, max_wait){
name = this._nameOptimize(name)
return this.promises[name]
},
_createOpenPromise(){
var aa, bb
var p = new Promise((a,b) => {aa = a, bb = b})
p.resolve = aa
p.reject = bb
return p
},
_nameOptimize(name){
name = name.trim()
if(name.endsWith(".js")){
name = name.substr(0, name.length - 3)
}
return name
}
}

[test.js]
!function(){
var printTest = function(s){
console.log("test", s)
}
var printTest2 = function(s){
console.log("test2", s)
}

Module.set("test", {
printTest,
printTest2
})
}()

[test2.js]
!function(){
Module.set("test2", function(s){
console.log("test", s)
})
}()

[main.html]
<script src="module.js"></script>
<script>
Module.load("test")
</script>
<script>
Module.get("test").printTest(1)

Module.load("test2").then(tes => tes(2))

Module.getAsync("test2").then(tes => tes(3))
</script>
test 1
test 2
test 3

ロードするときは Module.load を使います
module になるファイルは全体を !function(){} で囲んでグローバルに何も置かないようにして Module.set でセットします
読み込みは非同期なので Module.load や Module.getAsync で受け取る Promise を使います
Module.get はすでにロードされていないとエラーになるので
Module.get("test").printTest(1)

はエラーになることがあります

勢いで作ってはみたけど ロード済みじゃないと非同期になって書きづらいし もっと ES module に近い書き方なようにしておいたほうが 後からちゃんとした ES module に移行するときが楽かも