Skip to content
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

Add foreign JS integration article #14

Merged
merged 6 commits into from
Jan 9, 2025
Merged

Conversation

Swordlash
Copy link
Contributor

No description provided.

Copy link
Member

@Kleidukos Kleidukos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great post, I learned a lot.
I noticed some stuff to change, but fortunately nothing major!


## Using JavaScript backend with existing JavaScript tools

Any, even the most complex and technically beautiful undertaking is worthless if its fruits are not usable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Any, even the most complex and technically beautiful undertaking is worthless if its fruits are not usable.
Yet, even the most complex and technically beautiful undertaking is worthless if its fruits are not usable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


### Optimizing and bundling

Currently, `google-closure-compiler` is supported for minification of the bundle (see [previous blog](https://blog.haskell.org/report-of-js-code-minification/)). Let's try it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Currently, `google-closure-compiler` is supported for minification of the bundle (see [previous blog](https://blog.haskell.org/report-of-js-code-minification/)). Let's try it.
Currently, `google-closure-compiler` is supported for minification of the bundle (see the blog post on [JS code minification](https://blog.haskell.org/report-of-js-code-minification/)). Let's try it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

```

Notice we have to call `google-closure-compiler` with two input files: first is the `all.js` package generated by the compiler after bundling our library with all dependencies,
GHC rts and emscripten rts files; second, is the `all.externs.js` file that declares external variables for the minifier. Its purpose is twofold - first it instructs the compiler those are declared elsewhere and it should not fail with undeclared variable; second, it prohibits mangling those identifiers during minification.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
GHC rts and emscripten rts files; second, is the `all.externs.js` file that declares external variables for the minifier. Its purpose is twofold - first it instructs the compiler those are declared elsewhere and it should not fail with undeclared variable; second, it prohibits mangling those identifiers during minification.
GHC's RTS and emscripten RTS files; second, is the `all.externs.js` file that declares external variables for the minifier. Its purpose is twofold - It informs the compiler that those variables are declared elsewhere, as not to fail with an "undeclared variable" error, and it prevents the mangling of those identifiers during minification.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

import Data.Text qualified as T
```

We are going to use foreign import for initializing and destroying a button ripple effect. We will include this code in `js-sources` pragma of the cabalfile:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We are going to use foreign import for initializing and destroying a button ripple effect. We will include this code in `js-sources` pragma of the cabalfile:
We are going to use foreign import for initializing and destroying a button ripple effect. We will include this code in `js-sources` field of the package's cabal file:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

```

We are going to use foreign import for initializing and destroying a button ripple effect. We will include this code in `js-sources` pragma of the cabalfile:
```yaml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```yaml
```cabal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


Callbacks fully enable probably the most fascinating purpose of JavaScript backend, which is web programming. GHCJS has been around for quite some time now,
however it is both outdated (being a GHC fork requiring separate maintenance; currently stuck on 8.10) and cumbersome to use (often necessitating a separate setup, typically through Nix). In one of my previous companies, while evaluating potential options for rewriting the frontend, I decided to use PureScript. It was close enough to Haskell and very easy to set up - it can be installed directly through `npm`, has its own `stack`-like package manager `spago` with a suite of existing bundler plugins, and a blazing fast language server.
During this journey I was using [purescript-halogen](https://github.com/purescript-halogen/purescript-halogen) library - a typesafe, declarative VDOM framework based on the Elm Architecture.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a link to the Elm Architecture could be useful for the reader?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
```

And voila! It all works as before. The uncompressed bundle size is slightly bigger (844 KiB vs 803 KiB with `google-closure-compiler`) however we don't need any more workarounds,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
And voila! It all works as before. The uncompressed bundle size is slightly bigger (844 KiB vs 803 KiB with `google-closure-compiler`) however we don't need any more workarounds,
And voilà! It all works as before. The uncompressed bundle size is slightly bigger (844 KiB vs 803 KiB with `google-closure-compiler`) however we don't need any more workarounds,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (sorry I never know whether it's acute or grave)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*problemu (it's genitive) ;)


## Thanks!

Many thanks to [Serge S. Gulin](https://github.com/GulinSS) for his help and discussions on Matrix channel, and to [Hécate Kleidukos](https://gitlab.haskell.org/Kleidukos) for inviting me to write this blog. I want also to thank [Sylvain Henry](https://gitlab.haskell.org/hsyl20) and [Luite Stegeman](https://gitlab.haskell.org/luite) for our mail and PR discussions, and whole IOG GHC Engineering team for the joint effort of releasing the JS backend. Awesome work!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Many thanks to [Serge S. Gulin](https://github.com/GulinSS) for his help and discussions on Matrix channel, and to [Hécate Kleidukos](https://gitlab.haskell.org/Kleidukos) for inviting me to write this blog. I want also to thank [Sylvain Henry](https://gitlab.haskell.org/hsyl20) and [Luite Stegeman](https://gitlab.haskell.org/luite) for our mail and PR discussions, and whole IOG GHC Engineering team for the joint effort of releasing the JS backend. Awesome work!
Many thanks to [Serge S. Gulin](https://github.com/GulinSS) for his help and discussions on Matrix channel, and to [Hécate Kleidukos](https://gitlab.haskell.org/Kleidukos) for inviting me to write this blog post. I want also to thank [Sylvain Henry](https://gitlab.haskell.org/hsyl20) and [Luite Stegeman](https://gitlab.haskell.org/luite) for our mail and PR discussions, and whole IOG GHC Engineering team for the joint effort of releasing the JS backend. Awesome work!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


What's next? There is still a lot to do in terms of code size & performance, as well as integration with other tools:

- This cabal [PR](https://github.com/haskell/cabal/pull/10722) adds a new pragma `js-options` that allows to pass custom flags to `js-sources` preprocessor.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- This cabal [PR](https://github.com/haskell/cabal/pull/10722) adds a new pragma `js-options` that allows to pass custom flags to `js-sources` preprocessor.
- This cabal [PR](https://github.com/haskell/cabal/pull/10722) adds a new field, `js-options`, that allows to pass custom flags to `js-sources` preprocessor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@Kleidukos
Copy link
Member

@GulinSS Could I ask you to take a look?

```sh
mateusz@m12844:~/personal/halogen-blog$ ./run_example 1
(...)
+ npx google-closure-compiler --language_in UNSTABLE --compilation_level ADVANCED_OPTIMIZATIONS --warning_level QUIET --isolation_mode IIFE --assume_function_wrapper --emit_use_strict --js /home/mateusz/personal/halogen-blog/dist-newstyle/build/javascript-ghcjs/ghc-9.12.1/example1-0.1.0.0/x/example1/build/example1/example1.jsexe/all.js --js /home/mateusz/personal/halogen-blog/dist-newstyle/build/javascript-ghcjs/ghc-9.12.1/example1-0.1.0.0/x/example1/build/example1/example1.jsexe/all.externs.js --js_output_file ../dev/index.js
Copy link

@GulinSS GulinSS Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be add a small description why UNSTABLE with a link?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Added.

```sh
mateusz@m12844:~/personal/halogen-blog$ brotli -Z -o dev/index.js.br dev/index.js
mateusz@m12844:~/personal/halogen-blog$ du -h dev/index.js.br
76K dev/index.js.br
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow wow

@GulinSS
Copy link

GulinSS commented Jan 8, 2025

May be it would be nice to add few figures which demonstrate what you see in browser?

@Swordlash
Copy link
Contributor Author

It's in the videos. Not sure how that renders on the page but in github it works fine

@GulinSS
Copy link

GulinSS commented Jan 8, 2025

It's in the videos. Not sure how that renders on the page but in github it works fine

Ah! Finally found it, nice!

@Swordlash
Copy link
Contributor Author

@Kleidukos @GulinSS is it good to go?

Copy link
Member

@Kleidukos Kleidukos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If @GulinSS is happy, I am!

Copy link

@GulinSS GulinSS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me too!

@Kleidukos Kleidukos merged commit 1d01b1e into haskell:main Jan 9, 2025
2 checks passed
@GulinSS
Copy link

GulinSS commented Jan 9, 2025

Screenshot_20250109-131324
Video does not work. Seems affected only mobile @Kleidukos

@Kleidukos
Copy link
Member

Indeed I can reproduce

@Swordlash
Copy link
Contributor Author

Swordlash commented Jan 9, 2025 via email

@Swordlash
Copy link
Contributor Author

Swordlash commented Jan 9, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants