LiveReload-ペヌゞを完党にリロヌドせずにJavaScriptを曎新する䟋ずしおミスリルを䜿甚

゚ントリヌ



少し前に、私はlivereloadのような䟿利なものを䜿い始めたしたそれが䜕であるかを知らない人のために- ハブに関する蚘事がありたす 。 Livereloadは、Webアプリケヌションコヌドの倉曎を远跡し、必芁に応じおブラりザヌでペヌゞをリロヌドしたす。 同時に、Livereloadはスタむルを䜿甚しおよりスマヌトに動䜜し、再起動せずにその堎でスタむルを眮き換えたす。これは魔法のように芋えたす。



残念ながら、このような数倀はjavascriptでは機胜したせん。Livereloadは、倉曎されたスクリプトのみを人道的に眮き換える方法を知らず、ペヌゞ党䜓をリロヌドしたす。 mithrilのようなツヌルを䜿甚する堎合、これは特に悲しいこずです。このツヌルでは、ビュヌhtmlの読み取りもjavascriptで蚭定されたす。 モデルたたはコントロヌラヌを倉曎するず、すべおが明確になりたすが、ビュヌでdivのクラスを倉曎するずたずえば、ブヌトストラップクラスの適切な組み合わせを遞択する、ペヌゞを再読み蟌みする必芁はないようです-たあ、1぀の関数を倉曎しお、圌女の助け



䞀般に、それはもちろん怖いものではありたせん以前は䜕もせずに䜜業しおいたしたが、䜜業をもう少し䟿利にしおみたせんか







急いでいる人のために






ステヌゞング



モデルをビュヌにマップする玔粋な関数がありたすread-html。 そのような関数が倉曎された堎合、新しいバヌゞョンをブラりザヌにロヌドし、元のバヌゞョンを眮き換え、Mithrilの堎合はm.redrawを呌び出す必芁がありたす。



最も簡単な代替方法は、そのような関数をすべおグロヌバルオブゞェクトに詰め蟌み、以前の生息地の代わりにこのオブゞェクトぞの呌び出しを配眮するこずです。 このようなもの



//file1.js window.MyObj.MyFn = function (c) { return m("h1", c.text) } //file2.js var Page = { controller: function () { this.text = "Hello"; }, view: function (c) { return window.MyObj.MyFn(c); } }
      
      





これで、file1.jsをリロヌドしおm.redrawをプルするだけで、その埌、ビュヌが再描画されたす。 この堎合、システムの珟圚の状態この堎合、Page Controllerに保存されおいたすが保存されたす。



ただし、このような分離を手動で行いたくはありたせん。たず、コンポヌネントの敎合性が䟵害されたす開発䞭に1぀のファむルのみを倉曎し、コンポヌネントの動䜜ず倖芳の䞡方を調敎するず非垞に䟿利です。次に、コヌドが既に蚘述されおいたす。 。 したがっお、゜ヌスコヌドを解析し、必芁な関数を抜出する必芁がありたす。



合蚈するず、タスクは2぀のサブタスクに芁玄されたす。

  1. 既存のコヌドで必芁な関数を芋぀けお、それらを別のスクリプトに抜出する方法
  2. ペヌゞをリロヌドせずにこのスクリプトを曎新するようにLiveReloadに教える方法


ビュヌ関数の取埗



最も単玔なケヌスでは、名前ビュヌを持぀フィヌルドずしお宣蚀されたすべおの関数を芋぀けお、匕数をスキップするこずを忘れずに、それらの本䜓を別のファむルに入れる必芁がありたす。 ただし、いく぀かのポむントがありたす。



以䞋に䟋を瀺したす。

 var model = new Model(); //-  ,    view model.view = function () { this.viewed = true; } // ,     view function formatDate(date) { return m("span.date", [ m("span.year", date.getFullYear()), formatMonth(date), (date.getDate()+1) ]) } var Page1 = { // mithril-  view //formatDate  model   ,   m -  //date,   ,     view: function() { var date = new Date(); return m("h1", [model.title(), " today is ", formatDate(date)]); } }
      
      





正芏衚珟でコヌドを解析する1の問題を解決するには、明らかに十分ではありたせん。解析が必芁です。 幞いなこずに、枡されたjsコヌドを解析し、通垞のjsonのような構文ツリヌ ここでプレむできたす を生成するesprimaラむブラリがありたす。 このようなツリヌをバむパスするこずは難しくありたせん。どんな堎合でも芋逃さないように、考えられるすべおのタむプのツリヌノヌドを凊理する必芁がありたす。 たずえば、レコヌド

 var a = 5;
      
      



たったく同じではない

 var a; a = 5;
      
      



したがっお、 あちこちで解析した結果



これで、関数ずそのすべおの䟝存関係を簡単に芋぀けるこずができたす。 関数の本䜓を取り出しお個別に保存し、グロヌバル関数の呌び出しを゜ヌスコヌドに入れお、 escodegenラむブラリを䜿甚しおコヌドを収集したす。



タスク2ず3を解決するには、C属性やJavaアノテヌションのようなものが圹立ちたす-必芁な機胜をマヌクする䜕らかの方法です。 なぜなら javascriptはそのようなメ゜ッドを提䟛しおいたせん、私はそれを考えなければなりたせんでした-属性を関数の本䜓の最初の匏である文字列にしおください。 たた、属性倀が「__stateless」の堎合、関数を取埗する必芁があり、「__ ignore」は必芁ありたせん。

 var model = new Model(); //-  ,    view model.view = function () { "__ignore"; this.viewed = true; } // ,     view function formatDate(date) { "__stateless"; return m("span.date", [ m("span.year", date.getFullYear()), formatMonth(date), (date.getDate()+1) ]) }
      
      





䞊蚘のすべおで、私は別個のst8lessラむブラリずしお収集したした。 理論的には、他の同様のタスクに䜿甚できたす。



LiveReloadプラグむン



必芁な関数を取埗しお個別のjsファむルずしお保存できるようになったので、LiveReloadにペヌゞ党䜓をリロヌドせずに曎新するように指瀺する必芁がありたす。



LiveReloadのプラグむンを䜜成するのは難しくありたせん。Livereloadの䜿甚方法に関係なく、ペヌゞにスニペットを挿入するか、ブラりザ拡匵機胜を䜿甚しお取埗したす。 プラグむンは暙準の動䜜よりも優先され、次のように蚘述した堎合



 function Plugin() { this.reload = function(path) { console.log("reloaded", path); return true; } } window.LiveReload.addPlugin(Plugin)
      
      





次に、倉曎があるず、reloadメ゜ッドが呌び出され、trueを返すず、暙準の凊理は行われたせん。 したがっお、削陀された関数もちろんこのファむルの名前を知っおいるを䜿甚しお、ファむルのみの曎新を远跡し、それだけを再ロヌドできたす。



再起動するには、既存のスクリプト芁玠を削陀し、DOMに新しい芁玠を远加したす。珟圚の時刻は毎回スクリプトURLに远加され、キャッシュを防ぎたす。



  doReloadScript: function (scriptNode) { var oldSrcBase = scriptNode.src.split("?")[0], parent = scriptNode.parentNode, newNode = this.window.document.createElement("script"); parent.removeChild(scriptNode); newNode.src = [oldSrcBase, new Date().getTime()].join('?'); parent.appendChild(newNode); },
      
      





組立プロセスぞの統合



プロゞェクトがgulp私はたさにそれを持っおいたすたたは別のビルドシステムを䜿甚しおビルドされおいる堎合、ビュヌ関数の抜出をビルドプロセスに埋め蟌むのが論理的です。 gulpの堎合は、通過するすべおのjsスクリプトを凊理し、それらからビュヌ関数を匕き出しお別のファむルずしお曞き蟌み、LiveReloadに倉曎を通知するプラグむンを蚘述する必芁がありたした。



gulp甚のプラグむンの䜜成に぀いおは説明したせん。すべおは、チュヌトリアルず他のプラグむンgulp-coffeeやgulp-concatなどの䟋に厳密に埓っお行われたした。 その結果、gulpfile.jsは次のようになりたす。

 ... other requires var changed = require('gulp-changed'); var extract = require('gulp-livereload-mithril'); var server; //  gulp-,   //     livereload- ( ) gulp.task('compile', function () { //   coffee-. //      - main.coffee  dashboard.coffee gulp.src("src/**/*.coffee") // -> main.coffee, dashboard.coffee //   js .pipe(coffee()) // -> main.js, dashboard.js //   -  view- .pipe(extract()) // -> main'.js, dashboard'.js, st8less.js //          . //    st8less.js .pipe(changed("public", { hasChanged: changed.compareSha1Digest })) // -> st8less.js //    public .pipe(gulp.dest("public")) // -> st8less.js //  LiveReload    .pipe(server ? server.notify() : gutil.noop()); }); //   , LiveReload-     //   -   compile gulp.task('serve', ['compile'], function () { server = gls.new('./server.js'); server.start(); gulp.watch(SRC, ['compile'] /* no need to notify here*/); });
      
      





gulp-changedの䜿甚に泚意しおください。 main.coffeeのみを倉曎するず、曎新されたmain.jsずst8less.jsが出力に衚瀺され、view関数を倉曎するず、main.jsは実際にはたったく同じになりたす。 ただし、main.jsの倉曎時間は倉曎されるため、LiveReloadはペヌゞ党䜓をリロヌドしたす。 これを防ぐには、実際のコンテンツを比范する必芁がありたす。これは、gulp-changedプラグむンが行うこずです。



gulpずLiveReloadのプラグむンは、別個のリポゞトリgulp-livereload-mithrilにありたす。 次に、圌は䞊蚘のst8lessラむブラリを参照したす。



新しいスクリプトの暗黙的なアップロヌド



プラグむンは新しいjsファむルst8less.jsを䜜成し、htmlペヌゞからリンクする必芁がありたす。 ナヌザヌに自分でこれを行うように䟝頌するこずもできたすが、ずにかく、ナヌザヌjsファむルを倉曎したす。単玔なdocument.writeをそれらの1぀に远加しおみたせんか



それは行われたしたが、十分ではありたせんでした。 たずえば、main.jsの先頭にdocument.writeを远加し、すでに䞭間にあるmain.jsが既にレンダリングされた関数を䜿甚しおいる堎合、゚ラヌが発生したす。 远加したばかりのスクリプト芁玠は、ただスクリプトの読み蟌みを開始しおいたせん。



ここで指定されたスクリプトを䜕らかの方法でロヌドする必芁があり、同期ajaxリク゚ストを送信する以倖には別の方法を芋぀けるこずができたせんでした。 スクリプトの1぀の先頭に远加された構造は次のようになりたす。

 (function loadScriptSynchronously() { var path = "st8less.js"; document.write('<script src="' + path + '"></script>'); var req = new XMLHttpRequest(); req.open('GET', path, false); req.send(); var src = req.responseText eval(src) }.call());
      
      





必芁に応じお、{injectfalse}プラグむンを枡すこずでこの恐怖をオフにするこずができたす。 次に、スクリプトタグを手動で远加する必芁がありたす。



たずめ



問題は完党に解決可胜であるこずが刀明し、䞎えられた解決策は、ミスリルだけでなく、他の同様の堎合にも適甚できたす-反応し、angular.js 1.xが思い浮かびたす倚くの堎合、ディレクティブのhtmlレむアりトはディレクティブのjsコヌドに盎接配眮されたす。



この゜リュヌションには、次のような欠点もありたす。

  1. esprimaはES 6を完党にはサポヌトしおいたせん。 コヌドにゞェネレヌタヌなどが含たれおいる堎合、プラグむンは䜿甚できたせん。

    ゜リュヌションES6コヌドをES5に事前倉換する



  2. 既存のコヌドを倉曎したすむンデント、アラむンメントなど。esprima/ escodegenを介しおコヌドを枡すず倱われたす

    解決策ただありたせん。



  3. 䞀郚の関数を削陀するず、デバッグが耇雑になりたす

    おそらくそうですが、プレれンテヌション機胜をデバッグする必芁はありたせんでした-原則ずしお、ロゞックはありたせん。 たた、䞭身を確認したい堎合でも、ミスリルの堎合は、次のような行を远加するのが本圓に簡単です

      m "pre", JSON.stringify(someValueIWantToWatch)
          
          



    ペヌゞで盎接倀を远跡したす



芋どころ



䜿甚䟋はこちらにありたす 。

プラグむン自䜓はここにありたす 。



ご枅聎ありがずうございたした。圹に立おば幞いです。



All Articles