I'm trying to use the ES6 import syntax and keep running into errors.
This is my data type,
class UnionFind{
constructor(n){
this.items = n;
}
union(p, q){
}
connected(p, q){
}
find(p){
}
count(){
}
}
export default UnionFind
Saved in a file UnionFind.js
This the calling client,
import { UnionFind } from './unionFind';
const readline = require('readline');
const rl = readline.createInterface({
input:process.stdin,
output:process.stdout,
terminal:false
});
uf = new UnionFind(10)
rl.on('numbers', function (line) {
arr = number.split(' ')
console.log(arr);
});
This is saved in a file client.mjs
This is how I'm running it,
node --experimental-modules union-find/client.mjs
I get the following error,
(node:13465) ExperimentalWarning: The ESM module loader is experimental.
file:///Users/mstewart/Dropbox/data-structures-algorithms-princeton/union-find/client.mjs:1
import { UnionFind } from './unionFind';
^^^^^^^^^
SyntaxError: The requested module does not provide an export named 'UnionFind'
at ModuleJob._instantiate (internal/modules/esm/ModuleJob.js:89:21)
at <anonymous>
What am I doing wrong here?
In this case, use
import UnionFind from './UnionFind.js';
if you declared
export class UnionFind{ ....
then you use
import { UnionFind } from './UnionFind.js';
Also take a look at the file name: UnionFind.js . You are using './unionFind'. This is case sensitive
Related
How to include functions in namespace / module when don't have module?
example: I have a namespace:
namespace Java {}
in typescript, usually when we need a function in namespace or module, we add 'export':
namespace Java {
export function version() {
return "java8";
}
}
namespace JavaScript {
function JavaVer() {
return Java.version();
}
}
But if I set module to none:
// tsconfig
"module": "none",
If module is none, I cannot use import / export:
website/sourcecode/main.ts:17:21 - error TS1148: Cannot use imports, exports, or module augmentations when '--module' is 'none'.
17 export function version() {}
so what can I do?
image:
You can use a plain object:
TS Playground
const Java = {
version () {
return "java8";
},
};
const JavaScript = {
JavaVer () {
return Java.version();
},
};
const vJ = Java.version(); // string
const vJS = JavaScript.JavaVer(); // string
console.log(vJ === vJS); // true
It was answered in here: It's actually "can't have any imports or exports at the top level". Imports and exports inside namespaces are fine because they don't export anything from .ts file at runtime, and as long as file remains 'not a module' module=None works fine. Long explanation here
I need to import a JavaScript module from an in memory variable.
I know that this can be done using SystemJS and Webpack.
But nowhere can I find a good working example nor documentation for the same. The documentations mostly talks of dynamic import of .js files.
Basically I need to import the module like below
let moduleData = "export function doSomething(string) { return string + '-done'; };"
//Need code to import that moduleData into memory
If anyone can point to documentation that will be great
There are limitations in the import syntax that make it difficult to do if not impossible without using external libraries.
The closest I could get is by using the Dynamic Import syntax. Two examples follow: the first one is the original I wrote while the second one is an edit from a user that wanted to modernize it.
The original one:
<!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>
The modernized one:
function doimport (str) {
if (globalThis.URL.createObjectURL) {
const blob = new Blob([str], { type: 'text/javascript' })
const url = URL.createObjectURL(blob)
const module = import(url)
URL.revokeObjectURL(url) // GC objectURLs
return module
}
const url = "data:text/javascript;base64," + btoa(moduleData)
return import(url)
}
var moduleData = "export function hello() { console.log('hello') }"
var blob = new Blob(["export function hello() { console.log('world') }"])
doimport(moduleData).then(mod => mod.hello())
// Works with ArrayBuffers, TypedArrays, DataViews, Blob/Files
// and strings too, that If URL.createObjectURL is supported.
doimport(blob).then(mod => mod.hello())
You will however notice that this has some limitations on the way the import code is constructed, which may not precisely match what you need.
The simplest solution is probably to send the code of the module on the server for it to generate a temporary script to be then imported using a more conventional syntax.
let moduleData = await import("data:text/javascript,export function doSomething(str) { return str + '-done'; }");
and to test it
moduleData.doSomething('test');
Use nodejs flag --experimental-modules to use 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)
Further reading here
How It Works:
I first create the file with fs.writeFileSync
then I use import method's promise to load module and
pipe doSomething method call with "It Works!"
and then log the result of doSomething.
Credits: https://stackoverflow.com/a/45854500/3554534, https://v8.dev/features/dynamic-import, #Louis
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!
You can create component and Module on fly. But not from string. Here is an example:
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";
});
Here is the stackblitz
Based on Feroz Ahmed answer, here is a specific example to dynamically load a Vue 3 component from the server via socket.io.
Server-side (Node + 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>
For some weird reason, the suggested way of dynamically import()-ing a "data" URL throws an error: TypeError: Invalid URL when done from an npm package code.
The same "data" URL import()s without any errors from the application code though.
Weird.
const module = await import(`data:text/javascript;base64,${Buffer.from(functionCode).toString(`base64`)}`)
<script type="module">
import { myfun } from './myModule.js';
myfun();
</script>
/* myModule.js */
export function myfun() {
console.log('this is my module function');
}
index.js of imported npm module myLib
const Mod1 = require('./mod1');
const Mod2 = require('./mod2');
const Mod3 = require('./mod3');
module.exports = {
Mod1,
Mod2,
Mod3,
};
mod1.js
class Mod1 {
constructor(url) {
}
}
file using the above npm module
const Mod1 = require('myLib');
const instance = new Mod1();
This is throwing the following error when trying to run it:
const instance = new Mod1();
^
TypeError: Mod1 is not a constructor
How should I reference the class from a single import index.js so that I may be able to create an instance of the class?
There seems to be a slight mistake in your import, the actual import will be like:
const {Mod1} = require('myLib');
which will pull the class from the file and give it to you (ES6 feature)
you can also do it like:
const Mod1 = require('myLib').Mod1;
hope this helps.
How to export and use the ECMA6 class? This is what I am doing now:
parser.js
module.exports = class Parser {
static parse() {
}
static doNow() {
}
}
Now in another file, I am doing:
var Parser = require('parser')
Parser.parse();
When parse is called on Parser, I get an error saying
SyntaxError: Unexpected identifier
with Parser highlighted.
What could be the reason for this? What is the correct to export and import the class?
You try to call your module in an absolute way this is what causes problem.
I recommend using an IDE as webstorm or atom to not have this kind of problem in the future
try this :
var Parser = require('path/path/parser.js');
Parser.parse();
for es6 is :
export default class Parser {
static parse() {
}
static doNow() {
}
}
import Parser from './path/path/parser';
It's easier and more readable to do it like this:
class Parser {
static parse() {
}
static doNow() {
}
}
module.exports = Parser;
and in the requiring module:
const Parser = require('./path/to/module');
Parser.doNow();
// etc.
I tested this and it seems the issue is the path of parser.
File Structor
-index.js
-parser.js
index.js
var Parser = require('./parser')
console.log('parser',Parser.parse());
parser.js
module.exports = class Parser {
static parse() {
return 'hello there'
}
static doNow() {
}
}
Terminal
node index.js
parser hello there
What must the module code (writen in typescript) look like to be able to use it like this:
/// <reference path="./onoff.ts" />
//import * as onoff from "./onoff";
var onoff = require("./onoff");
var app = onoff();
var computers: Onoff.Computer[] = [];
app.start(computers);
I was sure it must be this, but it does not work:
import * as express from "express";
export module Onoff {
export class Computer {
}
export class OnoffApp {
start(computers:Computer[], port:number = 3489) {
...
}
}
export default function() {
return new OnoffApp();
}
}
Typescript complains:
service/example.ts(5,11): error TS2349: Cannot invoke an expression whose type lacks a call signature.
service/example.ts(7,16): error TS2503: Cannot find namespace 'Onoff'.
service/example.ts(8,21): error TS2503: Cannot find namespace 'Onoff'.
typings/express/express.d.ts(14,1): error TS6053: File 'typings/serve-static/serve-static.d.ts' not found.
typings/express/express.d.ts(28,34): error TS2307: Cannot find module 'serve-static'.
thank you very much! I have no Idea what I've done wrong...
Judging from the error description, moving the import outside of your module should fix your problem:
import * as express from "express";
export module Onoff {
...
}
You import your module as onoff but are trying to use Onoff
var onoff = require("./onoff");
^
var computers: Onoff.Computer[] = [];
^