te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>How to dynamically executeeval JavaScript code that contains an ES6 modulerequires some dependencies? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to dynamically executeeval JavaScript code that contains an ES6 modulerequires some dependencies? - Stack Overflow

programmeradmin3浏览0评论

I want my users to be able to use JavaScript as a scripting language inside my JavaScript application. In order to do so, I need to dynamically execute the source code.

There seem to be two main options for dynamically executing JavaScript:

a) Use eval(...) method ( or var func = new Function(...);) .

b) Add a <script> node to the DOM (for example by using $('body').append(...)).

Both methods work fine as long as I do not use any import statements in the dynamically executed source code. If I include import statements I get the error message Unexpected identifier.

Example user source code to be executed:

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

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

Example application code to illustrate a possible usage of that dynamic code:

a) Using eval

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

b) Using DOM modification:

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

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

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

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

If I specify no script type or use type="application/javascript" for option b), I get the Unexpected identifier error. If I use type="module" I get no error. The script tag is successfully added to the DOM, but the module code is not executed.

I first thought that might be due to asynchronous loading. However, waiting until loading of the script tag is finished did not work with type='module'. The loading mechanism works with type="application/javascript" but then ... again... import does not work.

Example code for async execution after script tag has been loaded:

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 patibility.
        script.onreadystatechange = callback;
        script.onload = callback;

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

--

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

If I hard-code the user source code in my index.html using <source type="module">, the module code is executed. Dynamically loading the module code does not seem to work. I use Chrome version 63.0.3239.108.

=> I. How can I force the execution of the <script type="module"> tag after dynamically adding it to the DOM? or

=> II. How can I eval script that contains import (and maybe export) statements? or

=> III. What would be a good way to allow the user source code to define dependencies that can be resolved dynamically?

Related questions and articles:

  • Execute JavaScript code stored as a string

  • /

  • How do I include a JavaScript file in another JavaScript file?

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

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

Further notes:

I know that the work flow of the examples, using, window.createTreeModel is not ideal. I used it here because the code is easy to understand. I will improve my over all work flow and think about stuff like security issues ... after I managed somehow to run user source code including its dependencies.

I want my users to be able to use JavaScript as a scripting language inside my JavaScript application. In order to do so, I need to dynamically execute the source code.

There seem to be two main options for dynamically executing JavaScript:

a) Use eval(...) method ( or var func = new Function(...);) .

b) Add a <script> node to the DOM (for example by using $('body').append(...)).

Both methods work fine as long as I do not use any import statements in the dynamically executed source code. If I include import statements I get the error message Unexpected identifier.

Example user source code to be executed:

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

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

Example application code to illustrate a possible usage of that dynamic code:

a) Using eval

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

b) Using DOM modification:

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

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

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

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

If I specify no script type or use type="application/javascript" for option b), I get the Unexpected identifier error. If I use type="module" I get no error. The script tag is successfully added to the DOM, but the module code is not executed.

I first thought that might be due to asynchronous loading. However, waiting until loading of the script tag is finished did not work with type='module'. The loading mechanism works with type="application/javascript" but then ... again... import does not work.

Example code for async execution after script tag has been loaded:

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 patibility.
        script.onreadystatechange = callback;
        script.onload = callback;

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

--

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

If I hard-code the user source code in my index.html using <source type="module">, the module code is executed. Dynamically loading the module code does not seem to work. I use Chrome version 63.0.3239.108.

=> I. How can I force the execution of the <script type="module"> tag after dynamically adding it to the DOM? or

=> II. How can I eval script that contains import (and maybe export) statements? or

=> III. What would be a good way to allow the user source code to define dependencies that can be resolved dynamically?

Related questions and articles:

  • Execute JavaScript code stored as a string

  • https://www.html5rocks./en/tutorials/security/sandboxed-iframes/#safely-sandboxing-eval

  • https://javascriptweblog.wordpress./2010/04/19/how-evil-is-eval/

  • How do I include a JavaScript file in another JavaScript file?

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

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

Further notes:

I know that the work flow of the examples, using, window.createTreeModel is not ideal. I used it here because the code is easy to understand. I will improve my over all work flow and think about stuff like security issues ... after I managed somehow to run user source code including its dependencies.

Share Improve this question edited Dec 27, 2017 at 9:09 Stefan asked Dec 26, 2017 at 12:41 StefanStefan 12.3k9 gold badges77 silver badges137 bronze badges 6
  • Use a transpiler. Don't use window to export, use export declarations. And notice that the code evaluation is probably going to be asynchronous, especially when dynamically loading dependencies, so prepare for that. – Bergi Commented Dec 26, 2017 at 12:56
  • @Bergi: Export does not work as long as the module code is not executed. Also see "Further notes". I managed to wait for the loading to be finished but that did not help. I updated my question with an example for considering the async loading. Could you please give an example on a transpiler could solve my issue? – Stefan Commented Dec 26, 2017 at 13:24
  • @Stefan He means use a transpiler to pile ES6 code to ES5 then execute the ES5 code. I'm not aware of any transpiler that works in the browser though. Most pile on your PC and you deploy ONLY ES5 code to the browser. – slebetman Commented Dec 26, 2017 at 13:42
  • @slebetman Most transpilers run anywhere (sans file loading). Have you never tried the live Babel REPL? – Bergi Commented Dec 26, 2017 at 17:40
  • 2 Have a look at 2ality./2019/10/eval-via-import.html – bennlich Commented Apr 7, 2021 at 5:09
 |  Show 1 more ment

2 Answers 2

Reset to default 10

With data uris or objectUrls and dynamic imports:

DataURI:

const code = 'export default function hello() { console.log("Hello World"); }';
const dataUri = 'data:text/javascript;charset=utf-8,' + encodeURIComponent(code);
const module = await import(dataUri);
console.log(module); // property default contains function hello now
const myHello = module.default;
myHello(); // puts "Hello World" to console

ObjectURL:

const code = 'export default function hello() { console.log("Hello World"); }';
const objectURL = URL.createObjectURL(new Blob([code], { type: 'text/javascript' }));
const module = await import(objectURL);
console.log(module); // property default contains function hello now
const myHello = module.default;
myHello(); // puts "Hello World" to console

Imports worked in my tests to, just if you use relative paths you might have to change the directory change prefixes (like ./ or ../), but since you have to code as text first, you just can replace it with regex before emulating.

After adding some log messages I found out that when using type="module":

  • $('body').append(script); does not execute the module code

  • body.appendChild(script); does asynchronously execute the module code but the events onload and onreadystatechange do not work, even if I use addEventListener(...) instead of script.onload =....

Following work around works for me. It modifies the user source code to include a call to a (temporal) global callback:

    var sourceCode =  editor.getText(); 

    window.scriptLoadedHook = function(){
        var model = window.createTreeModel();
        console.log('model:' + model);
        window.scriptLoadedHook = undefined;
    };

    var body = document.body;
    var script = document.createElement('script');
    script.type = 'module';
    script.innerHTML = sourceCode + "\n" + 
                       "if(window.scriptLoadedHook){window.scriptLoadedHook();}";           
    body.appendChild(script);   

I try now to find out how to use exports from the <script type="module"> tag to at least get rid of the global function window.createModel:

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

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论