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

Support for node-webkit #481

Closed
JPGygax68 opened this issue Sep 9, 2013 · 20 comments
Closed

Support for node-webkit #481

JPGygax68 opened this issue Sep 9, 2013 · 20 comments

Comments

@JPGygax68
Copy link

The following are suggestions.

The node-webkit project fuses NodeJS and webkit into a single runtime environment.

This makes it easy to require() modules intended for Node, which will (mostly) work. Sometimes though, you want to load modules into the browser "aspect" of node-webkit, and browserify is great for that. However, there are two problems:

  1. browserify's require() hides the one provided by the NodeJS aspect of node-webkit.
    (This can be worked around by simply putting all the node-dependent modules before the browserify-generated bundle)

  2. browserify generates a "process" object that hides the one provided by the NodeJS aspect of node-webkit.
    (This can be worked around as well, by assigning the original process object to a global variable.)

Even though work-arounds exist for both issues, I think it would be better if browserify could be told to a) provide its require() method under a different name and b) refrain from generating its own process object.

Other than that, thanks for providing a great tool!

@iwinux
Copy link

iwinux commented Nov 23, 2013

+1 on this issue

It would be great if browserify has an option for renaming require to sth else.

BTW, this is my workaround using grunt-browserify (which looks hacky):

browserify: {
  dist: {
    options: {
      postBundleCB: function (err, src, next) {
        // HACK: save Node's `require` before it gets overrided by browserify
        next(err, 'nodeRequire = require; ' + src)
      }
    }
  }
}

Then when referring to Node.js modules, you use sth like var fs = nodeRequire('fs')

@djcas9
Copy link

djcas9 commented Dec 6, 2013

+1

I can't seem to get it to work even using your suggested workaround and a few others. Any other hints on how you guys got it working correctly?

These are the two errors I continue to get regardless of what I try. :(

Uncaught ReferenceError: _ is not defined
Uncaught TypeError: Property 'require' of object [object Object] is not a function

@drkibitz
Copy link

drkibitz commented Dec 6, 2013

This may be or sound like a noob question, but why browserify for node-webkit? Is it part of an obfuscation step?

@JPGygax68
Copy link
Author

@mephux:

Here is the basic structure of my document (using Jade):

html(lang="en")
    head
        link(rel="stylesheet",href="style.css")
        script(type="text/javascript")
            require('./node-main')
        script(src="client.js", type="text/javascript")
    body
        include client/index
        include client/other-stuff

Here's the essence of node-main.js:

// In case node-webkit's require() is still needed later on:
window.requireNode = require;

// We cannot use the original names as node-webkit will reuse them in the window context.
window.node_dirname = __dirname;

// More Node-context stuff that might be needed in "window" code
window.argv = window.require('nw.gui').App.argv;
window.node_proc = process;

// Import the node-space modules that need to be available in all windows
window.qfs    = require('q-io/fs');
window.fs     = require('fs');
window.path   = require('path');
window._      = require('underscore');
window.Q      = require('q');

Owing to the fact that is is being require'd instead of being included directly by a script tag, node-main runs in the Node context; but (probably) because that require is inside a script tag, the window object is already available there.

As for client.js, that is the bundle generated by browserify.

@JPGygax68
Copy link
Author

Darn! I closed the issue by mistake - trying to re-open now...

@JPGygax68 JPGygax68 reopened this Dec 6, 2013
@JPGygax68
Copy link
Author

@drkibitz: No, it's not for obfuscation, I simply wanted to be able to use CommonJS rather than AMD. I'm not yet 100% sure that was a good idea within node-webkit :-).

@ghost
Copy link

ghost commented Dec 6, 2013

Can't you just do:

browserify main.js | toolThatTurnsRequireIntoSomethingElse > bundle.js

and then we don't need to bake this into browserify itself?

@thlorenz
Copy link
Collaborator

thlorenz commented Dec 6, 2013

I did exactly what @substack is suggesting in the ace editor version that gets auto refactored to be browserifyable and inline webworkers.
This is the relevant code

So you could implement a transform that works similarly.

@JPGygax68
Copy link
Author

@substack: that is one way to solve that part of the problem, though it requires an extra scan or parsing pass. It does not address the other part though (the mocked-up process object).

Maybe there is a misunderstanding on my part somewhere. I see browserify not only as a tool to make CommonJS require possible in the browser, but even more importantly as a way to automaticaly collect all js files that my code needs, and only those it needs. In fact, I'm mildly suprised that no equivalent tool seems to exist for node itself.

@ghost
Copy link

ghost commented Dec 20, 2013

You can use the new --bare to not override the node core builtin require() calls and --no-detect-globals to not insert a process shim. I've been doing:

browserify --no-detect-globals --bare -t coverify test/*.js | node | coverify

to run my tests with code coverage in node. This works in libraries that use core node APIs because browserify's shims are all turned off. I can run the test suite for node-mkdirp for example.

@ghost ghost closed this as completed Dec 20, 2013
@JPGygax68
Copy link
Author

@substack: thanks a ton! This is what I was hoping for.

@mkramb
Copy link

mkramb commented Jan 29, 2014

Just for info, to use this in context of grunt-browserify,
you have to define it like this:

browserify: {
  dist: {
    files: {
      'build/app.js': ['app/*.coffee']
    },
    options: {
      transform: ['coffeeify'],
      insertGlobals: false,
      detectGlobals: false
    }
  }
}

@adam-lynch
Copy link

@substack, @mkramb

Ok, that didn't work for me with gulp-browserify;

gulp.task('scripts', function(){
    gulp.src(paths.appEntryScript, {read:false})
        .pipe(browserify({
            transform: ['coffeeify'],
            extensions: ['.coffee'],
            insertGlobals: false,
            detectGlobals: false
        }))
        .pipe(rename('app.js'))
        .pipe(gulp.dest(paths.publicJS));
});

The only way I could get this all working is to use require for Browserify modules, nequire for Node modules and later rename to requireClient (including the instances of the string require in each module's Browserify boilerplate) and require respectively.

gulp.task('scripts', function(){
    gulp.src(paths.appEntryScript, {read:false})
        .pipe(browserify({
            transform: ['coffeeify'],
            extensions: ['.coffee']
        }))
        .pipe(replace('require', 'requireClient'))
        .pipe(replace('nequire', 'require'))
        .pipe(rename('app.js'))
        .pipe(gulp.dest(paths.publicJS));
});

Example usage:

$ = nequire 'jquery'
gui = require 'nw.gui'

gui.Window.get().on 'minimize', () -> 
    $('body').css('background', 'red');

@trevordixon
Copy link

@JPGygax68 Then to use node's require from a browerified bundle, I suppose you either call window.require or global.require?

@JPGygax68
Copy link
Author

@trevordixon Actually, my approach was to avoid mixing the two forms of require(), by using the Node variety from within a single top-level module only, executing in Node context. All modules imported from there automatically become available to all subsequently loaded scripts (which in my case are browserified).

@utensil
Copy link

utensil commented Jun 20, 2014

@JPGygax68 Can you provide a snippet to demonstrate your approach? I can't quite follow the solution and also want to make node-webkit and browserify working together.

@JPGygax68
Copy link
Author

It should be as simple as that (using Jade for brevity):

doctype html
html
  head
    title My Project
    script.
      // This script executes in Node context.

      var nodeRequire = require; // just in case you still need to node-require later

      // Anything require'd here will also execute in Node context.
      var aNodeModule = require('thenodemodule');

    link(rel="stylesheet", href="style.css") 

    // The following is a Browserify'd bundle and will run in Webkit context 
    script(src="main.js") 

  body
    h1 Hello World!

Apparently under Node-Webkit, embedded scripts execute in Node context, while external ones execute in Webkit context.

@utensil
Copy link

utensil commented Jun 21, 2014

@JPGygax68 Thanks, it helps a lot.

@swennemans
Copy link

@JPGygax68 Thanks for sharing 👍

@gregorym
Copy link

gregorym commented Apr 5, 2015

I'm still seeing this issue, especially when a dependency requires a node module.

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

No branches or pull requests