-
-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support ES module import in browser #53
Comments
Is this about this line: https://github.com/Elringus/DotNetJS/blob/cad9a87854fd860203d25991a55bb3a68fa11229/DotNet/Packer/LibraryGenerator/LibraryTemplate.cs#L11 ? It should only invoke in node environment, so |
If it's that line, can you please test if the following will work with angular:
|
It does not work, because global is not defined (so it produces the same error). You have to check if it exists before: // Get global shim as in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis#search_for_the_global_across_environments
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
factory(module.exports, getGlobal()); |
Wouldn't |
Or should it be |
Do you have any idea how we can make an automated test for this without involving angular? |
Execute the module in a browser context. Otherwise I think there is no way around implementing it inside an example project. |
Wait, but it does already work in browser (there is a sample project). The line with |
For webpack projects it is invoked because they are loaded as module (independent of later being executed in the browser). |
I'm currently using the library in react, no issues here. |
Might be that react is already polyfilling |
I tried it out with stencil now, other error: index-c37bab2d.js:2903 TypeError: Cannot set properties of undefined (setting 'dotnet')
at app-home.entry.js:10:21
at app-home.entry.js:11:3 undefined Happen with or without the
|
I think I was able to reproduce this in hello world sample with the browser module as you've suggested: <!DOCTYPE html>
Open console (Ctrl+Shift+I) to see the output.
<script type="module">
import * as dotnet from './Project/bin/dotnet.js'
dotnet.HelloWorld.GetHostName = () => "Browser";
window.onload = async function () {
await dotnet.boot();
const guestName = dotnet.HelloWorld.GetName();
console.log(`Welcome, ${guestName}! Enjoy your global space.`);
};
</script> — but using the getGlobal() doesn't seem to help: var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
if (typeof exports === 'object' && typeof exports.nodeName !== 'string')
factory(module.exports, getGlobal());
else factory(root.dotnet, root); |
I think this is related: umdjs/umd#127 and umdjs/umd#134 a comment suggests to switch to esm, but I don't now if this is compatible with VSCode related targets |
Seems like the only way around is publishing two |
global
leads to error in Angular Environment
I've added browser-es sample for testing (not working right now): https://github.com/Elringus/DotNetJS/blob/main/Samples/HelloWorld/browser-es.html Not sure what's the best approach to solve this (producing 2 libraries is not optimal, as it will require a lot of extra logic in C# packer). Guess the best workaround for now is polyfilling |
More likely it's just I'm bundling the react app with webpack, which statically links all imports. If I got it right, this issue only matters when you try to directly import dotnet in browser as ES module. You can still use it with any framework or inside any app and then bundle it. |
Angular also uses Webpack under the hood. |
Well React is using kind of UMD only: facebook/react#10021 |
Maybe angular is bundled differently, without static linking the deps? I mean, if bundle already has all the imports resolved/linked internally at build time, it shouldn't matter which import mechanism each individual dependency uses when the bundle is imported at runtime, right? |
Well yes angular is already using esm modules. |
If it'll solve the issue, sure. I've already tried doing that actually, but it didn't work, because we also need to share that global with dotnet/blazor internal stuff. But maybe I've missed something. |
It is at least solving the issue for angular, as angular seems to use a different way for importing the module. For importing the module via !(function (e, t) {
"object" == typeof exports && "object" == typeof module
? (module.exports = t())
: "function" == typeof define && define.amd
? define([], t)
: "object" == typeof exports
? (exports.dotnet = t())
: (e.dotnet = t());
})(this, () => // <== Here
... Then it is available via |
I've tried replacing Regarding angular, do you mean it's not related with the browser-es sample? In this case we'd need a minimal repro (without angular) as a starting point. Ideally, an automated test or at least a sample for manual testing. |
The "problem" with web modules (ES) is that they are incompatible with older package runtimes as they add the So, I support @Aloento view of generating an ES module first and then using rollup to create UMD/CommonJs, because generating them from ES modules is easy whereas generating ES modules from UMD is not feasible. But in the end this is way more work than any of us should invest for this problem. +var getGlobal = function () {
+ if (typeof self !== "undefined") {
+ return self;
+ }
+ if (typeof window !== "undefined") {
+ return window;
+ }
+ if (typeof global !== "undefined") {
+ return global;
+ }
+ throw new Error("unable to locate global object");
+};
+var global = getGlobal();
...
-})(this, () =>
+})(typeof self !== "undefined" ? self : this, () => Making it work in angular, and at least loading as web module: <script type="module">
import * as dotnet from "./Project/bin/dotnet.js";
window.onload = async function () {
await window.dotnet.boot();
const guestName = window.dotnet.HelloWorld.GetName();
console.log(`Welcome, ${guestName}! Enjoy your global space.`);
};
</script> But running into an error: dotnet.js:10763 Uncaught (in promise) ReferenceError: bodyJs is not defined
at Object.bind_method (dotnet.js:10763:49)
at s (dotnet.js:8876:64)
at Object.bindings_lazy_init (dotnet.js:8887:49)
at Object.bind_static_method (dotnet.js:10849:42)
at p (dotnet.js:13734:38)
at boot (dotnet.js:13980:34)
at async Object.exports.boot (dotnet.js:14138:9)
at async window.onload (global-module.html:9:9) |
Have you tried |
Yes, I loaded your |
Then I'm probably doing something wrong. I've tried using the getGlobal and self -> this stuff, but it still didn't work with the browser-es example. It's booting but assigned functions are not resolved by the runtime. |
maybe it did not come clear from my comment:
which means I am running into the same errors with your example, like |
Ok, so I've experimented a bit with migrating the library to es module; rewritten all the JS tests to es-style imports and switched webpack to module output: https://github.com/Elringus/DotNetJS/tree/feat/es-module/JavaScript/dotnet-runtime I'm currently stuck on how to better wrap the webpack-exported library with the C# packer. Previously I've just copy-pasted the UMD template, but now we have to somehow wrap/override the modules exported by webpack. I'm not familiar enough with all that stuff, so any suggestions are most welcome. |
webpack programmatic api is very useful And Microsoft.AspNetCore.NodeServices can help you to call NodeJS in C# |
This will require installing/running webpack when publishing C# project. I'd like to stick with manual patching if possible to simplify the process. |
Ah, looks like it's deprecated. dotnet/aspnetcore#12890 |
Let me work on this for your esm |
You mean |
I am now working on understanding your |
PR, please check it |
@elringus I have a similar problem. I'm using React with NX (webpack) and I got the Did you manage to get it to work in React? If so, did you configure anything special? |
I'm using it with React, yes. It's a default CRA, w/o any custom building or tooling tweaks. Builds with |
Just tried it... it works with CRA. Had to disable ESLint for the |
For NX it now works if I first create a react app using CRA, and use |
Running into this as well for my angular project... any workaround? |
Yes, try the workaround thats posted at the top the issue (inital issue description):
|
Yeah, adding this line didn't fix it, unfortunately :( (it did fix another error, but not this one) |
I'm not familiar with Angular, but regarding changing it on our side: the code comes from .NET's mono-wasm; iirc, they've improved it in .NET 7, so hopefully it'll work after we upgrade (#20). I'll also look into migrating to ES bundler after that. |
It's not about Angular. It's about the type of Javascript syntax that's generated. The generated JS implies variable declaration through expressions using commas (see Angular doesn't parse this syntax well. I think it should be changed to the more standard and common syntax regardless Angular can parse it or not. |
This is also a problem if you want to run the code in deno, since deno does not support umd. |
Hi again,
I tested the library with angular and it is running into an error:
Which is expected as the angular team came to the conclusion to not support global in their webpack build for broad compatibility. angular/angular-cli#9827 (comment)
I think this library should not rely on some other process to supply the variable.
So going forward you could use:
Workaround is adding
(window as any).global = window;
topolyfill.ts
The text was updated successfully, but these errors were encountered: