Nim icon indicating copy to clipboard operation
Nim copied to clipboard

Js output bloat

Open AmjadHD opened this issue 3 years ago • 3 comments

Summary

Remove dead code from the JS output.

Description

import std/dom

document.getElementById("foo").value = "bar"

expected:

document.getElementById("foo").value = "bar";

got: 720 lines of JS

tried adding {.nodecl.} to the definition of getElementById

import std/dom except getElementById

proc getElementById*(d: Document, id: cstring): Element {.importcpp, nodecl.}
document.getElementById("foo").value = "bar"

this saves 80 lines (function definitions)

but remains 640 lines of unused object definitions

var NTI587202750 = {size: 0,kind: 25,base: null,node: null,finalizer: null};
var NTI587202747 = {size: 0,kind: 25,base: null,node: null,finalizer: null};
var NTI587202746 = {size: 0, kind: 18, base: null, node: null, finalizer: null};
var NTI587202657 = {size: 0, kind: 22, base: null, node: null, finalizer: null};
var NTI587202749 = {size: 0, kind: 18, base: null, node: null, finalizer: null};
...

Why is nim producing this bloat ? I can imagine people being pushed away by this. Whether this is rational or not is debatable.

Alternatives

No response

Standard Output Examples

No response

Backwards Compatibility

No response

Links

No response

AmjadHD avatar Aug 10 '22 01:08 AmjadHD

Why is nim producing this bloat ?

They are type infos kept for inheritance.

ringabout avatar Aug 10 '22 02:08 ringabout

I didn't ask for them.

AmjadHD avatar Aug 10 '22 03:08 AmjadHD

I cannot reproduce.

import std/dom

document.getElementById("foo").value = "bar"

with -d:release, it generates

/* Generated by the Nim Compiler v1.7.1 */
var framePtr = null;
var excHandler = 0;
var lastJSError = null;
document.getElementById("foo").value = "bar";

ringabout avatar Aug 10 '22 03:08 ringabout

Sorry I was using a build system where -d:nodejs was set. Still you can see the same problem in dochack.js. I don't understand the need for these type definitions to be kept in the final output.

AmjadHD avatar Aug 10 '22 14:08 AmjadHD

They are actually type infos kept for copying, to emulate Nim value type semantics.

The compiler generally doesn't generate code it doesn't use, but I don't know if this is true for type information.

metagn avatar Aug 10 '22 14:08 metagn

These type definitions are supposed to be equivalent to those of the Javascript API, don't they ? Nim has the types defined (e.g in dom.nim), can it use them for generating code without actually keeping them in the final output ?

AmjadHD avatar Aug 10 '22 15:08 AmjadHD

The resulting output (specialized function for each type) could be larger than just using type information.

metagn avatar Aug 10 '22 18:08 metagn

https://github.com/nim-lang/Nim/issues/16144#issuecomment-734202467

You would get much better JS output by making the JS codegen use injectdestructors.nim and replacing the NimCopy calls by the moves it instead produces. Nim's move semantics are very nice for the JS codegen too.

Is this planned for v2 ?

AmjadHD avatar Aug 10 '22 21:08 AmjadHD

if you want to remove dead JS code in the output then just use Google's closure compiler

dom96 avatar Aug 10 '22 22:08 dom96

I'm aware of Google's closure compiler, I could as well just write js by hand or using typescript. The issue is about nim's js output.

AmjadHD avatar Aug 11 '22 10:08 AmjadHD

making the JS codegen use injectdestructors.nim

It seems to already do this specifically, unsure if it uses move semantics in general as much as it can.

I could as well just write js by hand or using typescript.

Well yeah, Nim isn't meant to be a drop-in replacement for JS. It's just a demonstration in this repo. The main use of compiling to JS is using the same code on multiple platforms. If people can find JS output optimizations that don't impede on compiler performance and can be done, then great, but it's not really a priority otherwise, and it won't really help that much.

My 400 kb game script with -d:release goes down to 166 kb with basic minification (mostly whitespace removed) and 20 kb when gzipped. Stuff like obfuscation would bring it down even more (mangled names are long). It goes down this much because Nim doesn't do much wrong other than add redundancy to the JS output for its own benefit, and that redundancy can be removed by using tools for optimizing regular JS. Trying to get rid of the redundancy through the compiler will just hinder it.

Also:

I can imagine people being pushed away by this.

Are there alternatives (i.e. languages that compile to more than just JS) that do better?

metagn avatar Aug 11 '22 13:08 metagn

The output is not particularly "bloated".

Araq avatar Aug 24 '22 22:08 Araq