从字符串变量导入模块
Import a module from string variable
我需要从内存变量中导入一个 JavaScript 模块。
我知道这可以使用 SystemJS 和 Webpack.
来完成
但是我在任何地方都找不到一个很好的工作示例,也找不到相同的文档。文档主要讨论 .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
工作原理:
- 我首先创建文件
fs.writeFileSync
- 然后我使用 import 方法的承诺来加载模块和
- pipe doSomething 方法调用 "It Works!"
- 然后记录 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";
});
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!
我需要从内存变量中导入一个 JavaScript 模块。 我知道这可以使用 SystemJS 和 Webpack.
来完成但是我在任何地方都找不到一个很好的工作示例,也找不到相同的文档。文档主要讨论 .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
工作原理:
- 我首先创建文件
fs.writeFileSync
- 然后我使用 import 方法的承诺来加载模块和
- pipe doSomething 方法调用 "It Works!"
- 然后记录 doSomething 的结果。
学分:
<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";
});
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');
基于
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!