HeinrichApfelmus / threepenny-gui

GUI framework that uses the web browser as a display.
https://heinrichapfelmus.github.io/threepenny-gui/
Other
439 stars 77 forks source link

Use http://electron.atom.io to make standalone applications #111

Open jeffreyrosenbluth opened 9 years ago

HeinrichApfelmus commented 9 years ago

I have already taken a look at Electron and very much liked what I saw. I think this is the most promising avenue for standalone applications with JavaScript.

jeffreyrosenbluth commented 9 years ago

That's great, let me know if you would like any help.

HeinrichApfelmus commented 9 years ago

@jeffreyrosenbluth Since you're offering help: Writing JS driver code the Electron shell should be no problem for me, but I wonder how or if it's possible to integrate this with cabal. It would be great if we could build some kind of cabal-electron package that offers post-build hooks to assemble package bundles from Haskell source files. I'm thinking of something similar to cabal-macosx.

jeffreyrosenbluth commented 9 years ago

Let me see what would be involved and whether is seems do-able.

jeffreyrosenbluth commented 9 years ago

This doesn't seem like it would be too difficult so let me see if I understand correctly what would be required. First, if we were going to do it "by hand" we would build the user's application, say app.hs, which imports the threepenny modules to a binary using cabal build. Then we would package this binary together with the JS driver code, a package.json file, and an index.html file if desired we could then use an asar archive to make this into a single app file. The package.json and index.html files would be the same for every app?

If this is correct I think that cabal integration would be fairly straight forward. Much of cabal-macosx deals with handling dependencies. I don't think we would have any dependencies that are not handled by regular cabal or are included in our static js code.

Let me know if you agree with this assessment and we can decide the best way to proceed.

HeinrichApfelmus commented 9 years ago

Yes, pretty much. Essentially, we need a post-build hook that copies the executable and the index.html and package.json files into a common directory, so that Electron can find a complete directory structure.

My problem is that I don't know much about Cabal. If you could figure out how to make such a post-build hook, then that would help me a lot.

jeffreyrosenbluth commented 9 years ago

I don't know that much about Cabal either but I think I'll be able to figure it out. I'll start working on it.

HeinrichApfelmus commented 8 years ago

I have successfully hooked up Threepenny-GUI to Electron.

I still don't know how to offer this functionality via .cabal files, though. Electron is an external dependency, the precompiled binary weighs 30-40MB (for version 0.33) for each platform. Application bundles have to be built by copying the relevant files.

jeffreyrosenbluth commented 8 years ago

I have to apologize, I thought I would have time to work on this, but I'm tied up on a large project for the foreseeable future. Sorry about that, I may still be able to do it, just not for a while.

HeinrichApfelmus commented 8 years ago

No worries, this is a completely voluntary activity, after all. :smile:

tr00per commented 8 years ago

I have successfully hooked up Threepenny-GUI to Electron.

Do you consider releasing a HOWTO for that?

bradrn commented 7 years ago

I think I've figured out how to hook up Threepenny-GUI to Electron. What you do is:

  1. Build the Haskell program and move the executable to the root of the program
  2. Add this as your package.json:
    {
       "name": "<name>",
       "version": "0.1.0",
       "main": "./main.js",
       "scripts": {
           "start": "electron ."
       }
    }
  3. Run npm install --save-dev electron
  4. Put this as your index.html:
    <webview src="http://localhost:<port>" style="width: 100%; height: 100%"></webview>
  5. Add the quickstart main.js file here.
  6. Add the following to main.js just before it says mainWindow.loadURL(url.format({ (line 19):
    const execFile = require('child_process').execFile;
    const child = execFile('./<haskell-program-name>');
  7. You might want to remove the lines of code which open the developer tools from main.js (it's well-commented, so they should be easy to find)
  8. Run the program using npm start

I've managed to get the sample programs distributed with threepenny-gui working using this method.

jerbaroo commented 7 years ago

Here's a method of doing this without custom HTML or moving an executable, it starts the app on a free port and waits until the Threepenny app is running before starting an Electron renderer process (display window).

import System.Environment (getArgs) import YourApp (start)

main :: IO () main = do [port] <- getArgs start (read port)

- Edit line 41 of `electron.js` to run **your** application, currently:
``` Node
child = spawn('stack', ['exec', 'your-app-exe', `${port}`]);

Now to run the whole thing:

npm install
stack build
./node_modules/.bin/electron electron.js

Edit: Note the only Stack specific instructions for this are: stack build; to build the binary, and line 41 of electron.js; to run the binary. These can be replaced respectively with another command to build your application and an edited form of line 41 to run the binary.

bradrn commented 7 years ago

... without moving the executable ...

The reason I used the method of 'moving the executable' instead of stack exec <program> is that the threepenny-gui executable can then be used on a computer without stack.


I'm going to create a repo with all the config files in it as an example of how to integrate threepenny-gui and electron. I'm having a bit of trouble with pushing the files though so I'll do it after I fix that.