nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.58k stars 1.47k forks source link

Auto generate import/export for ECMAScript #19625

Open iacore opened 2 years ago

iacore commented 2 years ago

Summary

Add export statement to end of generated Javascript file and auto generate import statement for Javascript libraries used in Nim (may need a new pragma). This will make the generated file a ES6 module, making it possible for Javascript bundlers like vite to process it. This will make publishing to npm easier, since there is no additional processing step needed to make to work with tools like vite or rollup.

Alternatives

The language user generate the boilerplate code themselves.

Additional Information

Discussed in https://forum.nim-lang.org/t/3755

juancarlospaco commented 2 years ago

See https://github.com/juancarlospaco/nodejs

iacore commented 2 years ago

See https://github.com/juancarlospaco/nodejs

Unrelated. I want proper ES Module support to import any other module, not only node modules.

juancarlospaco commented 2 years ago

It has the export and class in a macro, maybe provide some pseudo code of whats your design... 🤷

tandy-1000 commented 2 years ago

Summary

Add export statement to end of generated Javascript file and auto generate import statement for Javascript libraries used in Nim (may need a new pragma). This will make the generated file a ES6 module, making it possible for Javascript bundlers like vite to process it. This will make publishing to npm easier, since there is no additional processing step needed to make to work with tools like vite or rollup.

Alternatives

The language user generate the boilerplate code themselves.

Additional Information

Discussed in https://forum.nim-lang.org/t/3755

I'm very interested in this myself also, as I'm currently trying to use Nim with NPM packages and vite (hydrogen-view-sdk and later @metabrainz/brainzplayer).

I wrote the following code with @juancarlospaco's help. This allows you to write import statements which will work with vite.

import std/jsffi

func importModule*(module: cstring) {.importjs: "import #".}

template importFromModule*(module, library: static[cstring]) =
  assert module.len > 0 and library.len > 0, "Argument must not be empty string"
  {.emit: ["import ", module, " from '", library, "';"].}

The next issue I'm facing is supporting import statements like: import olmLegacyJsPath from '@matrix-org/olm/olm_legacy.js?url'; which have a result that needs to be accessed from Nim.

I found @alaviss's macros which may be helpful: https://github.com/alaviss/setup-nim/blob/ng/src/private/utils.nim#L145 But unfortunately these are designed for require.js rather than vite.

To make std/jsffi more useful and make this happen, these macros could be modified and some more code could be written to:

If anyone wants to work on this / discuss, please get in contact :).

juancarlospaco commented 2 years ago
  • Support ES classes

https://juancarlospaco.github.io/nodejs/nodejs/jsclasses

Has Getters, Static methods, Private methods, export, constructors, tests, docs, and more. This can be added to stdlib as Experimental, just copy the code and PR it, std/jsfetch was Experimental too and produced no concrete critical bugs so...

tandy-1000 commented 2 years ago
  • Support ES classes

https://juancarlospaco.github.io/nodejs/nodejs/jsclasses

Has Getters, Static methods, Private methods, export, constructors, tests, docs, and more. This can be added to stdlib as Experimental, just copy the code and PR it, std/jsfetch was Experimental too and produced no concrete critical bugs so...

This is going to be useful, before using it to make class wrappers we will need to add support for mix-ins / inheritance and generators.

Edit: https://github.com/juancarlospaco/nodejs/pull/11

iacore commented 2 years ago

I think generating export statement for public stuff should be built into the JS compiler backend.

extern let default_import: string {.jsdecl, module: "modulefoo".}
extern let named_import: string {.jsdecl, module: "modulefoo", name: "named_import".}

let named_export* = 1

would generate something like:

import default_import from "modulefoo"
import {named_import: named_import} from "modulefoo"

export const named_export = 1