My Setup
I'm compiling my .ts module 'FooModule' into an UMD module in Visual Studio 2015. I would like to extend this UMD syntax, so that the module will be injected into the global object as fallback when no module loading system is present, and I would like to automate this task as part of the build-process.
The UMD Syntax
When compiling a TypeScript module with the UMD syntax (Universal Module Definition syntax), modules that are compatible with both RequireJS and NodeJS are emitted:
foo-module.ts
export class Foo {
// ...
}
... is compiled into:
foo-module.js
(function (factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
} else if (typeof define === 'function' && define.amd) {
define(["require", "exports"], factory);
}
})(function (require, exports) {
"use strict";
var Foo = (function () {
function Foo() {
}
return Foo;
}());
exports.Foo = Foo;
});
Fallback to Global Inject
However, as part of the Universal part of UMD, I would like my module to be usable without any module loading system as well. My module has no dependencies.
This is usually done by adding a third case as a fallback for when neither the RequireJS nor the NodeJS module system are present, which will effectively inject into the global object. For foo-module, this would look like:
(function (global, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
} else if (typeof define === 'function' && define.amd) {
define(["require", "exports"], factory);
} else {
// *****************************
factory(null, global.FooModule || (global.FooModule = {})); // <- This part.
// *****************************
}
})(this, function (require, exports) {
"use strict";
var Foo = (function () {
function Foo() {
}
return Foo;
}());
// In browsers, this means 'window.FooModule.Foo = Foo'.
exports.Foo = Foo;
});
I believe this would suffice in all cases when there are no external dependencies (assuming no two modules with the same name have been loaded this way).
I understand I can just rewrite manually after each build, but how could I automate this task (or something with identical results) as part of a build-process in Visual Studio (2015)?
I understand I can just rewrite manually after each build, but how could I automate this task (or something with identical results) as part of a build-process in Visual Studio (2015)?
You will have to create this yourself.
More
There are a few variations of UMD : https://github.com/umdjs/umd the one you want is fallback browser global : https://github.com/umdjs/umd/blob/master/templates/returnExports.js
This is not the version in TypeScript because global is pretty much no module system.
Related
I am attempting to compile a small C++ example that uses the standard library into wasm for use with a basic javascript entrypoint (not generated glue code). Unfortunately, when loading the module, I receive the following error:
TypeError: WebAssembly.instantiate(): Import #0 module="wasi_snapshot_preview1" error: module is not an object or function
I have attempted building using wasisdk and standalone llvm previously, but had similar issues. There doesn't seem to be information about working around this rather cryptic error.
Firstly, before I go deeper, is it even possible to build C++ code that uses data structures from the standard library into standalone wasm? I am unsure of whether I should be able to get this working given that wasm is still in its early days, but I might be doing something incorrectly. In my experience, almost every built-in data structure and string causes issues, even if I overload new and delete to rule-out some memory allocation issues.
For more details, my system is MacOS 10.14, and I'm running Chrome 80. I am using the latest version of emsdk from the github to compile.
My apologies for the influx of code blocks, but I am unsure of a better example. I've reduced the examples to the minimum as well as I could.
This is my bash build script:
em++ source.cpp \
--std=c++17 \
-flto \
-fno-exceptions \
-Os \
-o output.wasm \
-s "EXPORTED_FUNCTIONS=['_animate']" \
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \
C++: I get the error as soon as I use a data structure such as a standard unordered map.
#ifdef __cplusplus
#define extern_c_begin() extern "C" {
#define extern_c_end() }
#else
#define extern_c_begin()
#define extern_c_end()
#endif
#include <unordered_map>
std::unordered_map<int, int> map;
int use_map() {
// if I use the map at all, I get the error
map.insert({1, 2});
return (int)map.size();
}
extern_c_begin()
// call into js
void hello_js(void);
int animate(long arg) {
int size = use_map();
hello_js();
return size;
}
extern_c_end()
Finally, my javascript/index.html:
<!DOCTYPE html><html><head></head><body>
<script type="module">
"use strict";
(async () => {
try {
const wasmInfo = {
instance : null,
memoryHeap : null,
env : {}
};
wasmInfo.env["hello_js"] = () => {
console.log("in js, call from wasm");
};
// error on load
const wasmLoadResult = await WebAssembly.instantiateStreaming(
fetch("./output.wasm"),
{env : wasmInfo.env}
);
wasmInfo.instance = wasmLoadResult.instance;
function animate(t) {
requestAnimationFrame(animate);
try {
console.log(wasmInfo.instance.exports.animate(t));
} catch (e) {
console.error(e);
}
}
requestAnimationFrame(animate);
} catch (err) {
console.error(err);
}
})();
</script></body></html>
This seems to happen with practically every data structure. I even tried a third-party library called robin_hood to replace the map, but that has the same issue.
Is there a solution?
You need to implement all the system calls required by your program. Take a look at the output of wasm-objdump to see a list of all the imports required by your program.
Firstly, before I go deeper, is it even possible to build C++ code that uses data structures from the standard library into standalone wasm?
Yes. Proof:
// app.cpp
#include <vector>
using std::vector;
typedef long int i32;
extern "C" {
i32 myFunction(i32 myNumber) {
vector<i32> myVector{ 666, 1337 };
return myVector[0] + myVector[1] + myNumber;
}
}
emcc -Os -s INITIAL_MEMORY=64kb -s MAXIMUM_MEMORY=64kb -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_STACK=0kb -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_myFunction']" -Wl,--no-entry "app.cpp" -o "app.wasm"
// javascript
(async () => {
const response = await fetch('app.wasm');
const file = await response.arrayBuffer();
const imports = { wasi_snapshot_preview1: { proc_exit: () => { } } } // dummy placeholder function, a sacrifice to the emscripten god who demands it
const wasm = await WebAssembly.instantiate(file, imports);
const { myFunction } = wasm.instance.exports;
const myNumber = myFunction(123);
console.log(myNumber); // 2126
})();
i have the following Problem with ember-i18n:
Error: Attempting to inject an unknown injection: 'service:i18n'
at Registry.validateInjections (ember.debug.js:2303)
at ember.debug.js:1538
at runInDebug (ember.debug.js:5813)
at Object.runInDebug (ember.debug.js:17396)
at instantiate (ember.debug.js:1532)
at lookup (ember.debug.js:1385)
at Container.lookup (ember.debug.js:1304)
at Class.lookup (ember.debug.js:32564)
at Class._internalGetHandler (router-ext.js:107)
at Class._getHandlerForEngine (router-ext.js:84)
I use the ember-i18n plugin in an ember engine. My i18n initializers addon/instance-initializers/i18n.js:
export default {
name: 'i18n',
initialize: function(applicationInstance) {
const i18nService = applicationInstance.lookup('service:i18n');
i18nService.set('defaultLocale', window.I18n.defaultLocale);
i18nService.set('locale', window.I18n.locale);
}
};
In my index route (routes/index.js) i have the following code:
import Ember from 'ember';
export default Ember.Route.extend({
i18n: Ember.inject.service(),
actions: {
didTransition() {
Ember.run.scheduleOnce('afterRender', this, function() {
console.log(this.get('i18n').t('error_empty_user_data'));
// ....
});
}
}
});
How can I declare the i18n service?
I use the ember-18n 4.5.0 Version and the 2.10.0 ember-cli Version.
The initializer should run after i18n one.
export default {
name: 'i18n',
after: ['ember-i18n'],
initialize: function(applicationInstance) {
const i18nService = applicationInstance.lookup('service:i18n');
i18nService.set('defaultLocale', window.I18n.defaultLocale);
i18nService.set('locale', window.I18n.locale);
}
};
Can someone explain the difference between the one-argument form and the two-argument form of Init when creating a c++ node.js addon?
void Init(Local<Object> exports) {}
void Init(Local<Object> exports, Local<Object> module) {}
In general you could always use the second method template, but exports or module provide different options.
Using the following example:
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "test", MyTest);
}
will add the function test as a "function property" on your exports object.
So you could use the following JS code and it would, for example, print it out to the stdout using the test function from your exports object:
const test = require('./path/to/node/addon/addon.node');
test.test('my message');
On the other hand:
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", MyDummyCallback);
}
Provides you with the full module (module) and allows you to override your exports. You could call something like this from JS:
const test = require('./path/to/node/addon/addon.node');
test('test');
Will print your test message to the tty using the overridden module.
I'm using rtti in haxe nme. It works well when targeting flash but when compiling to a cpp target I receive the following error.
error C2039: '__rtti' : is not a member of 'Class_obj'
I'm doing this...
public function doSomething(type:Class<Dynamic>):Void {
var typeInfo:String = untyped type.__rtti;
}
I also tried...
public function doSomething <T:Infos> (type:Class<T>):Void {
var typeInfo:String = untyped type.__rtti;
}
What should I do?
Make it looser! :Dynamic instead of :Class<Dynamic>
public function doSomething(type:Dynamic):Void {
var typeInfo:String = untyped type.__rtti;
}
Say I have a test.ts and a MY_MODULE.d.ts file:
MY_MODULE.d.ts:
module MY_MODULE
{
export class Config {
UserId : string;
};
export function Init( config : Config );
}
test.ts:
/// <reference path="MY_MODULE.d.ts" />
MY_MODULE.Init(<MY_MODULE.Config>{ UserId: 'Josh' });
My question: Is it possible to fix either the definition file or the .ts file so that the cast in the latter is unnecessary?
Use export interface Config instead of export class Config.
Typescript will infer the correct type based on the signature of the object, so the cast is not necessary.
Copying the code into the playground, a couple of compile errors were immediately picked up. Firstly, Init needs an implementation.
Secondly, the Config class does not have a constructor.
The following code compiles cleanly:
module MY_MODULE
{
export class Config {
UserId : string;
};
export function Init( config : Config ) {
}
}
var myConfig = new MY_MODULE.Config();
myConfig.UserId = 'Josh'
MY_MODULE.Init(myConfig);
It would be better to define a constructor for Config as follows:
module MY_MODULE
{
export class Config {
UserId : string;
constructor(userId : string) {
this.UserId = userId;
}
};
export function Init( config : Config ) {
}
}
MY_MODULE.Init(new MY_MODULE.Config('Josh'));