2017-12-26 22 views
3

JavaScriptアプリケーションでJavaScriptをスクリプト言語として使用できるようにしたいと考えています。そのためには、ソースコードを動的に実行する必要があります。動的に実行する/ eval ES6モジュールを含むJavaScriptコード/いくつかの依存関係が必要ですか?

動的にJavaScriptを実行するための2つの主要なオプションがあるように思える:

A)eval(...)法(またはvar func = new Function(...);)を使用します。

b)DOMに<script>ノードを追加します(たとえば、$('body').append(...)を使用して)。

動的に実行されるソースコードにimportステートメントを使用しない限り、どちらの方法も問題なく動作します。 importステートメントを含めると、エラーメッセージUnexpected identifierが表示されます。

例のユーザのソースコード実行される:

import Atom from './src/core.atom.js': 

window.createTreeModel = function(){ 
    var root = new Atom('root'); 
    root.createChildAtom('child'); 
    return root; 
} 

そのダイナミックコードの可能な使用法を説明するための例のアプリケーションコード:

A)を使用して)評価

var sourceCode = editor.getText(); 
window.createTreeModel = undefined; 
eval(sourceCode); 
var model = window.createTreeModel(); 
treeView.setModel(model); 

Bを用いDOMの変更:

var sourceCode = editor.getText(); 
window.createTreeModel = undefined; 

var script = "<script >\n"+ 
      sourceCode + "\n" +    
      "</script>"; 

$('body').append(script); 

var model = window.createTreeModel(); 
treeView.setModel(model); 

スクリプトの種類を指定しないか、オプションb)にtype="application/javascript"を使用すると、Unexpected identifierというエラーが発生します。 type="module"を使用してもエラーは発生しません。 scriptタグは正常にDOMに追加されますが、モジュールコードは実行されません。

まず、非同期読み込みの可能性があると考えました。ただし、スクリプトタグの読み込みが完了するまで待つことはtype='module'では機能しませんでした。読み込みメカニズムはtype="application/javascript"で動作しますが、再び... importは機能しません。スクリプトタグがロードされた後に非同期実行のための

例コード:

function loadScript(sourceCode, callback){ 
     // Adding the script tag to the head as suggested before 
     var head = document.getElementsByTagName('head')[0]; 
     var script = document.createElement('script'); 
     script.type = 'application/javascript'; 
     script.innerHTML = sourceCode; 
     //script.async=false; 

     // Then bind the event to the callback function. 
     // There are several events for cross browser compatibility. 
     script.onreadystatechange = callback; 
     script.onload = callback; 

     // Fire the loading 
     head.appendChild(script); 
    } 

-

loadScript(sourceCode, function(){ 
     var model = window.createModel(); 
     console.log('model:' + model); 
    }); 

私はハードコードの私のindex.htmlでユーザーのソースコードを<source type="module">、使用している場合モジュールコードが実行されます。動的にモジュールコードをロードすることは機能していないようです。私はChromeのバージョン63.0.3239.108を使用しています。

=> I. <script type="module">タグを動的にDOMに追加した後、どのように強制実行できますか?または

=> II。 import(およびおそらくエクスポート)ステートメントを含むスクリプトをどのように評価できますか?または

=> III。ユーザーソースコードで動的に解決できる依存関係を定義できるようにするにはどうすればよいでしょうか?

関連の質問と記事:

  • Why is script.onload not working in a Chrome userscript?

  • さらにノートは:

    私は例のワークフロー、使用して、window.createTreeModelが理想的ではないことを知っています。コードは分かりやすいのでここで使用しました。すべての作業フローを改善し、セキュリティ問題のようなものについて考えてみましょう...私はどうにかしてその依存関係を含むユーザーソースコードを実行するように管理しました。

    +0

    トランスファーを使用してください。エクスポートに 'window'を使用せず、' export'宣言を使用してください。そして、特に動的に依存関係を読み込んでいるときは、コード評価が非同期になる可能性があるので注意してください。 – Bergi

    +0

    @Bergi:モジュールコードが実行されていない限り、エクスポートは機能しません。 「その他の注意事項」も参照してください。私はローディングが完了するのを待つことができたが、それは役に立たなかった。私は非同期読み込みを考慮した例を使って質問を更新しました。私は、蒸散器が私の問題を解決できるかどうかの例を教えてください。 – Stefan

    +0

    @Stefan彼は、トランスバータを使ってES6コードをES5にコンパイルし、次にES5コードを実行することを意味します。私はブラウザで動作する蒸散器は認識していません。ほとんどの場合、PCでコンパイルし、ブラウザにのみES5コードをデプロイします。 – slebetman

    答えて

    1

    type="module"を使用するときに私が発見したいくつかのログメッセージを追加した後:

    • $('body').append(script);

    • body.appendChild(script);が非同期モジュールのコードを実行しないモジュールのコードを実行しませんが、イベントonloadscript.onload =...の代わりにaddEventListener(...)を使用しても、onreadystatechangeは機能しません。

    次の回避策は私の仕事です。これは、グローバルコールバックへの呼び出しが含まれるように、ユーザのソースコードを変更します。

    var sourceCode = editor.getText(); 
    
        window.scriptLoadedHook = function(){ 
         var model = window.createModel(); 
         console.log('model:' + model); 
         window.scriptLoadedHook = undefined; 
        }; 
    
        var body = document.getElementsByTagName('body')[0]; 
        var script = document.createElement('script'); 
        script.type = 'module'; 
        script.innerHTML = sourceCode + "\n" + 
             "if(window.scriptLoadedHook){window.scriptLoadedHook();}";   
        body.appendChild(script); 
    

    私は、少なくともグローバル関数window.createModelを取り除くために<script type="module">タグからの輸出を使用する方法を見つけるために今すぐ試してみてください。

    How to import es6 module that has been defined in <script type="module"> tag inside html?

    関連する問題