dhall-lang / dhall-haskell

Maintainable configuration files
https://dhall-lang.org/
BSD 3-Clause "New" or "Revised" License
916 stars 213 forks source link

Publish GHC.js output to npm? #1860

Open JAForbes opened 4 years ago

JAForbes commented 4 years ago

Trying out dhall using toolchains web developers are already familiar with, could make dhall even more approachable to other communities/audiences.

E.g. npx dhall <command> would install the package, run the command and then uninstall the package. Most JS devs have npx on their machine (even if they don't realise it) and https://www.npmjs.com/package/dhall is not taken (at the time of writing).

I'm not sure if this is inadvisable for other reasons, (e.g. maybe the JS build is limited in some way).
In that case, maybe it makes sense to publish the binaries to the npm registry instead - to get the exact same affect without involving ghc.js.

Gabriella439 commented 4 years ago

@JAForbes: I don't have any objections to doing this; I just need help with the NPM-specific parts because I have never used NPM before.

We should probably reserve the name dhall for a native JavaScript implementation, but we could call the package derived from the Haskell implementation dhall-haskell or something similar.

For reference, here is what the directory tree looks like for the output of the GHCJS build (slightly truncated for clarity):

$ tree result
result
├── bin
│   ├── dhall
│   └── dhall.jsexe
│       ├── all.js
│       ├── all.js.externs
│       ├── index.html
│       ├── lib.js
│       ├── manifest.webapp
│       ├── out.frefs.js
│       ├── out.frefs.json
│       ├── out.js
│       ├── out.stats
│       ├── rts.js
│       └── runmain.js
├── lib
│   ├── ghcjs-8.4.0.1
│   │   ├── dhall-1.32.0
│   │   │   ├── Dhall
│   │   │   │   ├── Binary.js_dyn_hi
│   │   │   │   ├── Binary.js_hi
│   │   │   │   ├── …
│   │   │   │   ├── Version.js_hi
│   │   │   │   └── Version.js_p_hi
│   │   │   ├── Dhall.js_dyn_hi
│   │   │   ├── Dhall.js_hi
│   │   │   ├── Dhall.js_p_hi
│   │   │   ├── Paths_dhall.js_dyn_hi
│   │   │   ├── Paths_dhall.js_hi
│   │   │   ├── Paths_dhall.js_p_hi
│   │   │   ├── libHSdhall-1.32.0-CshM77PedRE5DNyCkSSjoI.js_a
│   │   │   └── libHSdhall-1.32.0-CshM77PedRE5DNyCkSSjoI_p.js_a
│   │   ├── package.conf.d
│   │   │   └── dhall-1.32.0-CshM77PedRE5DNyCkSSjoI.conf
│   │   └── x86_64-linux-ghcjs-8.4.0.1-ghc8_4_2_20180420
│   │       └── libHSdhall-1.32.0-CshM77PedRE5DNyCkSSjoI-ghcjs8.4.0.1.js_so
│   └── links
└── nix-support
    └── propagated-build-inputs

If all we need is JavaScript code that can be executed by NPM, that is essentially what the ./bin/dhall and ./bin/dhall.jsexe provide.

For example, the ./bin/dhall script is a runnable node script:

$ cat ./result/bin/dhall
#!/nix/store/p0r56cns3ibjlwkh052mpczsrrs25wlh-nodejs-slim-6.14.3/bin/node 
var h$currentThread = null;
var h$stack = null;
var h$sp = 0;
var h$initStatic = [];
var h$staticThunks = {};
var h$staticThunksArr = [];
var h$regs = [];
var h$r1 = 0;
var h$r2 = 0;
…

$ ./result/bin/dhall <<< '2 + 2'
4

... and the build also includes the same code without the initial shebang line in ./result/bin/dhall.jsexe/all.js:

$ cat ./result/bin/dhall.jsexe/all.js
var h$currentThread = null;
var h$stack = null;
var h$sp = 0;
var h$initStatic = [];
var h$staticThunks = {};
var h$staticThunksArr = [];
var h$regs = [];
var h$r1 = 0;
var h$r2 = 0;
var h$r3 = 0;
…

... in case you want to insert your own custom shebang line (e.g. without the dependency on Nix).

I also put up a pull request to make it easier for others who have Nix installed to inspect the GHCJS build product for themselves:

https://github.com/dhall-lang/dhall-haskell/pull/1861

If you would like to know more about the various files in that directory tree I can do my best to answer, although I'm still a bit of a GHCJS novice myself.

JAForbes commented 4 years ago

Ok great! Yeah that looks to be all we need 👍

In order to be compatible with npx/npm we just need to generate a package.json with a few entries

{ "name": "dhall-haskell"
, "version": "<dhall-version>"
, "bin": "./result/bin/dhall.jsexe/all.js" 
, "files": "./result/bin/dhall.jsexe/all.js"
}

We'd probably want to add licence, repository, author, homepage to the JSON as well, and possible keywords as well.

I'm not sure how dhall's CI is configured but I imagine this is the basic process:

  1. Set up CI to be authenticated to publish npm packages docs
  2. Obtain the version number for the release somehow (a variable, a server call?)
  3. Generate the package.json with the included version number
  4. Run npm publish
Gabriella439 commented 4 years ago

@JAForbes: Is there a way to do a test publication to verify that the package is runnable via npx? I can always release a test 0.1 version if necessary, but I wasn't sure if there was a more idiomatic solution

kedashoe commented 4 years ago

npx will check your $PATH first. So you can do something like

  1. npm pack from the directory containing your package.json to create a tarball of your package
  2. make a directory to test it out, /tmp/foo or what have you
  3. cd in there and run npm install /absolute/path/to/tarball/from-step-1
  4. this should install the package you created in step 1 in /tmp/foo/node_modules
  5. it should also create /tmp/foo/node_modules/.bin, where your executable specified by the bin field in your package.json should be
  6. add /tmp/foo/node_modules/.bin to your PATH
  7. npx name-of-your-command

Note you can name your command by giving an object to bin in package.json, eg bin: { "dhall-haskell": "./result/bin/dhall.jsexe/all.js" }. I don't use npx much myself, I'm not sure how much magic it does or how much running a locally packed package will do to verify it would work with npx. I would guess just running the first 3 steps and then trying to execute your installed "binary" would be enough?

JAForbes commented 4 years ago

You can also publish a prerelease with a tag:

npm version 0.0.0-alpha-1
npm publish --tag alpha

This will prevent this release from being installed without specifically opting into that tag or release.

Then you can run npx dhall-haskell@alpha or npx dhall-haskell@0.0.0-alpha-1 to test.

You can also unpublish within 72 hours of publishing, even if it isn't an alpha. This is generally seen as bad practice, but I think in this case a valid option as no-one should be depending on this package yet.