从字符串变量导入模块

Import a module from string variable

我需要从内存变量中导入一个 JavaScript 模块。 我知道这可以使用 SystemJSWebpack.

来完成

但是我在任何地方都找不到一个很好的工作示例,也找不到相同的文档。文档主要讨论 .js 文件的动态导入。

基本上我需要像下面这样导入模块

let moduleData = "export function doSomething(string) { return string + '-done'; };"
//Need code to import that moduleData into memory

如果有人能指出文档那就太好了

使用nodejs标志--experimental-modules使用import ... from ...;

node --experimental-modules index.mjs
index.mjs:
import fs from 'fs';
let fileContents = "export function doSomething(string) { return string + '-done'; };"
let tempFileName = './.__temporaryFile.mjs';

fs.writeFileSync(tempFileName, fileContents);
console.log('Temporary mjs file was created!');

import(tempFileName)
    .then((loadedModule) => loadedModule.doSomething('It Works!'))
    .then(console.log)


延伸阅读 here

工作原理:

  1. 我首先创建文件 fs.writeFileSync
  2. 然后我使用 import 方法的承诺来加载模块和
  3. pipe doSomething 方法调用 "It Works!"
  4. 然后记录 doSomething 的结果。

学分, https://v8.dev/features/dynamic-import,@Louis

<script type="module">
    import { myfun } from './myModule.js';
    myfun();
</script>

/* myModule.js  */
export function myfun() {
    console.log('this is my module function');
}

您可以即时创建组件和模块。但不是来自字符串。这是一个例子:

name = "Dynamic Module on Fly";
const tmpCmp = Component({
  template:
    '<span (click)="doSomething()" >generated on the fly: {{name}}</span>'
})(
  class {
    doSomething(string) {
      console.log("log from function call");
      return string + "-done";
    }
  }
);
const tmpModule = NgModule({ declarations: [tmpCmp] })(class {});

this._compiler.compileModuleAndAllComponentsAsync(tmpModule).then(factories => {
  const f = factories.componentFactories[0];
  const cmpRef = this.container.createComponent(f);
  cmpRef.instance.name = "dynamic";
});

这是stackblitz

import 语法存在局限性,如果不使用外部库,即使不是不可能,也很难做到。

我能得到的最接近的是使用 Dynamic Import 语法。示例如下:

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<script>
    var moduleData = "export function hello() { alert('hello'); };";
    var b64moduleData = "data:text/javascript;base64," + btoa(moduleData);

</script>
<script type="module">

    async function doimport() {
      const module = await import(b64moduleData);
      module.hello();
    }

    doimport();

</script>

</body>
</html>

但是您会注意到,这对构建导入代码的方式有一些限制,可能与您的需要不完全匹配。 最简单的解决方案可能是将模块的代码发送到服务器上,让它生成一个临时脚本,然后使用更常规的语法导入。

let moduleData = await import("data:text/javascript,export function doSomething(str) { return str + '-done'; }");

并进行测试

moduleData.doSomething('test');

基于, here is a specific example to dynamically load a Vue 3 component from the server via socket.io.

Server-side(节点+socket.io)

socket.on('give-me-component', (data: any, callback: any) => {

  const file = fs.readFileSync('path/to/js/file', 'utf-8');

  const buffer = Buffer.from(file).toString('base64');
          
  callback(`data:text/javascript;base64,${buf}`);

});

Client-side (Vue 3 + socket.io-client)

socket.emit('give-me-component', null, async (data: any) => {

  // Supposes that 'component' is, for example, 'ref({})' or 'shallowRef({})'
  component.value = defineAsyncComponent(async () => {

    const imp = await import(data);

    // ... get the named export you're interested in, or default.

    return imp['TheNamedExport_or_default'];

  });

});

... 

<template>
  <component :is="component" />
</template>

NodeJS:

    // Base64 encode is needed to handle line breaks without using ;
    const { Module } = await import(`data:text/javascript;base64,${Buffer.from(`export class Module { demo() { console.log('Hello World!') } }`).toString(`base64`)}`)
    let instance = new Module()
    instance.demo() // Hello World!