{"id":13408466,"url":"https://github.com/praeclarum/Netjs","last_synced_at":"2025-03-14T13:31:19.342Z","repository":{"id":15418131,"uuid":"18150376","full_name":"praeclarum/Netjs","owner":"praeclarum","description":"Compile .NET assemblies to TypeScript and JavaScript","archived":false,"fork":false,"pushed_at":"2019-10-16T04:16:22.000Z","size":3298,"stargazers_count":961,"open_issues_count":29,"forks_count":134,"subscribers_count":77,"default_branch":"master","last_synced_at":"2024-07-31T20:30:46.660Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/praeclarum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-26T19:10:45.000Z","updated_at":"2024-07-29T06:26:52.000Z","dependencies_parsed_at":"2022-08-30T05:21:29.489Z","dependency_job_id":null,"html_url":"https://github.com/praeclarum/Netjs","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praeclarum%2FNetjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praeclarum%2FNetjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praeclarum%2FNetjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praeclarum%2FNetjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/praeclarum","download_url":"https://codeload.github.com/praeclarum/Netjs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243584231,"owners_count":20314719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T20:00:53.034Z","updated_at":"2025-03-14T13:31:19.318Z","avatar_url":"https://github.com/praeclarum.png","language":"C#","readme":"# Netjs\n\n[![Build Status](https://app.bitrise.io/app/fa94597fdbce95b1/status.svg?token=LNyVUJAH3rRjRIbtl0pvng)](https://app.bitrise.io/app/fa94597fdbce95b1)\n\nNetjs is a .NET to TypeScript and JavaScript compiler. It uses multiple stages to produce JavaScript for your web apps.\n\n\u003cimg src=\"Images/Explanation.png\" /\u003e\n\nYou start by compiling whatever code you want into its own assembly. Portable Class Libraries work great for this, but it really doesn't matter. You can even pass EXEs.\n\n```bash\nnetjs Library.dll\n```\n\nThis produces a TypeScript file. You can use this file as is if the rest of your app is written in TypeScript.\n\nIf you want JavaScript (with no dependencies), then pass this file along with a tiny mscorlib to the TypeScript compiler:\n\n```bash\ntsc -t ES5 mscorlib.ts Library.ts --out Library.js\n```\n\nYou can now include Library.js in any app because it is fully linked (you will get build errors if anything is missing).\n\n```html\n\u003cscript src=\"Library.js\" type=\"text/javascript\"\u003e\u003c/script\u003e\n```\n\nAnd that's it. You can write apps and reuse the portable parts in web apps!\n\n\n## Installation\n\n```bash\ndotnet tool install -g netjs\n```\n\n### Install TypeScript\n\nThe TypeScript compiler is needed to convert from TypeScript files to JavaScript.\n\nFirst, install [Node](http://nodejs.org/download/).\n\n```bash\nsudo npm install -g typescript\n```\n\n\n## Compiling Code\n\nNetjs works with .NET assemblies built with any compiler ([limitations][Limitations] not withstanding).\n\n### Compile to TypeScript\n\n```bash\nnetjs Library.dll\n```\n\nThis will output a TypeScript file named `Library.ts` containing all the code from `Library.dll` and any other assemblies referenced in its directory.\n\n### Compile to JavaScript\n\n```\ntsc -t ES5 mscorlib.ts Library.ts --out Library.js\n```\n\nThis compiles the library code along with a small implementation of mscorlib. The files are merged and output as a single JavaScript file `Library.js`.\n\n### ECMAScript 3 Compatibility\n\nIn case you need your code to run in es3 environment (like, well, IE8), you have to get rid of accessors as they are not supported.\nPassing `--es3` as an argument would result in creating of getter/setter methods instead of fields with accessors.\n\n```\nnetjs Library.dll --es3\n```\n    \nLibrary.dll:\n\n```csharp\nclass Person\n{\n    private string name;\n    public string Name\n    {\n        get { return name; }\n        set { name = value; }\n    }\n}\n```\n\nLibrary.ts:\n\n```csharp\nclass Person extends NObject\n{\n    name: string;\n    SetName(value: string): void\n    {\n        this.name = value;\n    }\n    GetName(): string\n    {\n        return this.name;\n    }\n}\n```\n\nAnd then compile TypeScript for ES3. Also use es3 compatible mscorlib.\n\n```bash\ntsc -t ES3 mscorlib.es3.ts Library.ts --out Library.js\n```\n\nSince all the references and assignments of all fields with accessors, including native ones, are replaced with methods invocations, you have to provide a corresponding implementation. In `mscorlib.es3.ts` all accessors are replaced with getter/setter methods.\n\n\n## Philosophy\n\n[History][] is filled with other IL to JS compilers, why Netjs?\n\nBecause I am not happy with the JavaScript generated by current solutions.\n\nThe best solutions currently generate a lot of code in an attempt to maintain all the finer points of .NET semantics. The philosophy of Netjs is that .NET and JavaScript's semanantics are *close enough* that idiomatic JavaScript can be generated from any .NET library. Sure we have to work around some of .NET's features, but the majority of code should be clean JavaScript. \n\nWell, that's almost true - JavaScript's idioms don't exactly match .NET's. However, TypeScript's come a lot closer. For this reason, Netjs leverages the TypeScript compiler. This also performs a great \"first unit test\" on the generated code because the TypeScript compiler is very strict and is good at catching errors.\n\nWhen I declare a class with properties in C#,\n\n```csharp\nclass Person {\n    public DateTime DateOfBirth { get; set; }\n    public int Age {\n        get {\n            var now = DateTime.Now;\n            return (new DateTime (dob.Year,now.Month,now.Day) \u003e= dob) ? \n                now.Year - dob.Year : \n                now.Year - dob.Year - 1;\n        }\n    }\n}\n```\n\nThe code generated should be idiomatic JavaScript. And it is:\n\n```csharp\nvar Person = (function (_super) {\n    __extends(Person, _super);\n    function Person() {\n        _super.call(this);\n        this.DateOfBirth = null;\n    }\n    Object.defineProperty(Person.prototype, \"Age\", {\n        get: function () {\n            var now = DateTime.Now;\n            var flag = DateTime.op_GreaterThanOrEqual(new DateTime(this.DateOfBirth.Year, now.Month, now.Day), this.DateOfBirth);\n            return (!flag) ? (now.Year - this.DateOfBirth.Year - 1) : (now.Year - this.DateOfBirth.Year);\n        },\n        enumerable: true,\n        configurable: true\n    });\n    return Person;\n})(NObject);\n```\n\nThere's a tiny wrapper placed around the class definition that is typical of JavaScript code avoiding name conflicts. There is the use of a tiny `__extends` function that establishes a class hierarchy using JavaScript's prototype chain. The rest is standard JavaScript.\n\nI want to make life easier for the machine by generating clean idiomatic code, but I also want it to be easier for us developers. \n\nWhen it comes time to use the Person class from JavaScript, that code should also be clean and idiomatic:\n\n```html\n\u003cscript\u003e\n    var p = new Person();\n    p.DateOfBirth = new DateTime(1980, 7, 23);\n    document.getElementById(\"age\").textContent = p.Age;\n\u003c/script\u003e\n```\n\n\n\n## History\n\nNetjs is not the first project that compiles .NET IL to JavaScript. It is, in fact, my second attempt at such an app. The first worked, but wasn't good enough for release.\n\nMicrosoft built their own named Project V. It was glorious, as was the amount of JavaScript it created. \"Hello world\" generated gigabytes of JavaScript. Serisously, I once calculated that the heat death of the universe would occur before it had finished outputting a foreach loop. You see, the JavaScript it output rigorously obeyed .NET semantics - it was as if a virtual machine vomitted all over your code. Glorious. Anyway, Microsoft cancelled the project.\n\nThen the world was blessed with [JSIL][]. This is Project V done right. It's still a virtual machine vomitting all over your code, but it's a clean nice kind of vomit that is measured in megabytes instead of gigabytes. It's powerful enough to compile the BCL and MonoGame - a truly powerful compiler. It's going to generate a lot code and you're might end up with a loading screen, but it does its job well.\n\n\n## Limitations\n\n* **Namespaces are ignored**\n* mscorlib.ts is a **tiny subset** of the full BCL\n* **Overloaded methods** generally work, but have trouble with:\n    - One overload being virtual and another not (it hurts my head trying to get this to work)\n    - Overloads that have the same argument count and accept values that can be null (runtime type checking is used)\n    - Overloaded constuctors that call different base constructors probably don't work\n* **Async** does not work\n* **Gotos** only sometimes work\n* **Regexes** have some problems:\n    - Named groups don't work (we rely on the browser's regex implementation)\n    - Match Group Index only works if you capture everything\n* Integer casts with the expectation of performing a Truncate operation don't work ()\n* **Seriously,** watch it with those overloads\n\nIf any of these bother you, then please go use [JSIL][]. \n\n[JSIL]: http://jsil.org\n\n\n## Thank you!\n\nNetjs owes the majority of its intelligence to [Mono.Cecil][cecil], [NRefactory][], and [ILSpy][]'s decompiler. Without these projects, Netjs would not exist. Thank you!\n\n[cecil]: http://mono-project.com/Cecil\n[NRefactory]: https://github.com/icsharpcode/NRefactory\n[ILSpy]: http://ilspy.net\n\n\n## License\n\n**The MIT License (MIT)**\n\nPlease see \u003ca href=\"LICENSE.txt\"\u003eLICENSE.txt\u003c/a\u003e for details.\n","funding_links":[],"categories":["Compiler","Compilers, Transpilers and Languages","编译器、透明机和语言","C#","C# #","编译器（Compiler）","Table of Contents"],"sub_categories":["Languages"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpraeclarum%2FNetjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpraeclarum%2FNetjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpraeclarum%2FNetjs/lists"}