Browserify document is undefined - node.js

i just found browserify, which sounds really cool. However i try to append a canvas element to the body(filename : Renderer.js):
window.document.body.appendChild(this.canvas)
module.exports = Renderer
And i also have a main.js
var Renderer = require("Renderer.js")
var r = new Renderer();
So i build the bundle like this:
browserify main.js -o bundle.js
And when i start the project:
node server.js
I get the following error message
ReferenceError : document is not defined (if only document.body)
And window is not defined (when window.document.body)
Can someone explain this behaviour and how to fix it?

Did you try to run that browserify code on the server? Please do not, as in the server there is not window element, whereas node only has global. Instead, you need to use your browser to download the browserified code and execute on your browser.
Note that, browserify library is mainly to bundle packages for client to use require styled call.

Related

How to use Webpack loaders in a Node app?

Is there a way to use Webpack loaders in a Node app / Run a Node app in a Webpack environment?
For instance I've got a webpack config that has a style-loader. In my Node app I do the following:
import style from 'style.css'
console.log(style.someClass)
I wanna run it like $ node app.js
I've got an idea that might work, based on the Webpack NodeJS API. What if we put the code that we want to be able to use the Webpack environment (with the configured module loaders) into a module:
appModule.js:
import style from 'style.css'
console.log(style.someClass)
And require it with the following:
app.js:
import Webpack from 'webpack'
import MemoryFS from 'memory-fs'
...
webpackConfig.entry = 'appModule.js'
webpackConfig.output = 'appModule-out.js'
let compiler = Webpack(webpackConfig)
let mfs = new MemoryFS()
compiler.outputFileSystem = mfs
compiler.run(function (err, stats) {
require(webpackConfig.output)
})
Probably it won't work because the require looks for the output on the physical FS... Can we require from the memory FS? I have not tried it yet - Any idea?
Webpack loaders aren't transpilers or interpreters, they simple gather assets that are then handled off to something like SASS or a text concatenator; within the confines of Webpacks environment.
Thus it is not possible to reuse them in the way you want, because while you can of course import and call them (they're still just functions + classes), they don't convert CSS to JSON objects (they don't do this) as you have written in your desired example.
It looks like you just need a JS implementation of a css parser - have a look at https://github.com/reworkcss/css
You should be able to create a compilation targeting the node environment which you can ultimately run by simply calling node output.js and this will immediately execute the entry point module.
Be aware, in case that you're using a newer version of Node.js, that Webpack doesn't support the ES2015 module syntax, so you'll have to configure Babel for Node.js as well to transform the modules.

How to use node module in client code?

I've installed ReactJs module in my nodejs application, so React appeared in node_modules directory. But I can't use it in client javascript because there is no reference.
So what is the best way to add such a reference ?
(Of course I can manually copy react.js script to scripts folder and add reference manually but it leads to code duplication and looks ugly)
Browserify is the tool you are looking for. It takes Node modules and wraps them so you can require() them in client side JavaScript code.
Example from Browserify's readme
Whip up a file, main.js with some require()s in it. You can use
relative paths like './foo.js' and '../lib/bar.js' or module paths
like 'gamma' that will search node_modules/ using node's module
lookup algorithm.
var foo = require('./foo.js');
var bar = require('../lib/bar.js');
var gamma = require('gamma');
var elem = document.getElementById('result');
var x = foo(100) + bar('baz');
elem.textContent = gamma(x);
Export functionality by assigning onto module.exports or exports:
module.exports = function (n) { return n * 111 }
Now just use the browserify command to build a bundle starting at
main.js:
$ browserify main.js > bundle.js
All of the modules that main.js needs are included in the
bundle.js from a recursive walk of the require() graph using
required.
To use this bundle, just toss a <script src="bundle.js"></script>
into your html!

Overcome differences in node and browserify path resolving

I'm writing a module for a react app that needs to be included on both the backend and frontend.
At some point in my code, I'm requiring some svg file (for which I use a browserify module, but this has nothing to do with the question).
For example I have in my ./src/js/components/tools/svg.js the following bit of code:
// ...
var BACKEND = /* code to detect if this is running on browser or on node */;
var svg;
if ( BACKEND ) {
svg = require("./../../../icon/" + this.props.icon + ".svg");
} else {
svg = require("./src/icon/" + this.props.icon + ".svg");
}
// ....
I use browserify's require option to require all the svg files at bundle-time:
browserify({
paths: ['./src/icon'],
})
.transform(/* svg tansformer */)
.require(glob.sync("./src/icon/*.svg")) // <-- svg's get added here
.add("./src/main.js"); // main entry point
However this conflicts with how node resolves the filenames. It cannot find ./src/icon/ from ./src/js/components/tools/svg.js.
This is why I have to guard the require with the BACKEN clause. This breaks my eyes though and I would like to just be able to write:
var svg = require('./src/icon/' + this.props.icon + '.svg');
I've tried two things so far:
fix node to find ./src/icon
I can use export NODE_PATH=`cwd` to allow node to look for src/icon from ./. This allows me to write:
var svg = require('src/icon/' + this.props.icon + '.svg');
in the backend. But, since browserify only accepts paths that start with ./ (thus, ignoring src/icon) this will not resolve on the frontend.
fix browserify to use ../../../icon/
Haven't got this to work either because of the same reason: browserify only accepts paths that start with ./.
It's considered bad practice doing conditional requires when using Browserify because it can't evaluate the code at "compile time" and will always attempt to load all the files.
To load different files in the browser environment than on node is easy:
Add a "browser" field to your package.json that points to the browser main file. Use "main" for the node main file. Then just require the module.
You can do the same thing with sub folders within your project. Just add a package.json file with "private": true and both, the main and the browser properties and require the folder path.

How to use Gulp to create a separate vendor bundle with Browserify from Bower components

I'm using Gulp and Browserify to package my Javascript into 2 separate bundles: application.js and vendor.js.
How do I bundle the vendor package if my vendor libraries are installed with Bower?
In my gulpfile, I'm using the following modules:
var gulp = require("gulp");
var browserify = require("browserify");
var debowerify = require("debowerify");
var source = require("vinyl-source-stream");
Assuming that I have only the Phaser framework installed with bower (for this example), my Gulp task to create the application package looks like this:
gulp.task("scripts-app", function () {
browserify("./app/javascripts/index.js")
.external("phaser")
.pipe(source("application.js"))
.pipe(gulp.dest("./tmp/assets"));
});
Meanwhile, the vendor task looks like this:
gulp.task("scripts-vendor", function () {
browserify()
.transform(debowerify)
.require("phaser")
.pipe(source("vendor.js"))
.pipe(gulp.dest("./tmp/assets"));
});
When I run this Gulp task, I get an error that states Error: Cannot find module 'phaser' from and then all the directories it search through (none of which are the bower_components directory).
Any ideas about how to package these up successfully are greatly appreciated. Thanks!
Answered my own question:
When using require in the Gulp task, you need to supply a path to a file, not just a name.
gulp.task("scripts-vendor", function () {
browserify()
.transform(debowerify)
.require("./bower_components/phaser/phaser.js")
.pipe(source("vendor.js"))
.pipe(gulp.dest("./tmp/assets"));
});
Notice that require("phaser") became require("./bower_components/phaser/phaser.js").
Doing this works, although the bundle takes forever to build (around 20 seconds). You're probably better of just loading giant libraries/frameworks directly into your app through a <script> tag and then using Browserify Shim.
This let's you require() (in the NodeJS/Browserify sense) global variables (documentation).
Seems like you figured out how to require the bower file. Hopefully you'll only have to bundle it once initially, and not every build. Including the library via a script tag isn't a bad idea. Another technique I'm using is to use scriptjs (a polyfill would work too), to async load whatever vender libraries I need, but make sure to include any/all require's after the script loads. For example, your index.js could be like:
$script.('/assets/vendor', function() {
var phaser = require('phaser');
//rest of code
});
It's especially nice for loading cdn files or having the ability to defer loading certain libraries that aren't necessarily used in the core app by every user, or loading libraries after client-side routing.

How to "require" text files with browserify?

I am using browserify (using browserify-middleware)
how can I require simple text files, something like:
var myTmpl = require("myTmpl.txt");
I cheked stringify plugin for browserify but the code in the documentation is not working with browserify V2
require() is really best for just javascript code and json files to maintain parity with node and to improve readability of your code to outsiders who expect require() to work the way it does in node.
Instead of using require() to load text files, consider using the brfs transform. With brfs, you maintain parity with node by calling fs.readFileSync() but instead of doing synchronous IO as in node, brfs will inline the file contents into the bundle in-place so
var src = fs.readFileSync(__dirname + '/file.txt');
becomes
var src = "beep boop\n";
in the bundle output.
Just compile with -t brfs:
browserify -t brfs main.js > bundle.js
More discussion about why overloading require() too much is a bad idea: http://mattdesl.svbtle.com/browserify-vs-webpack
stringify:
https://github.com/JohnPostlethwait/stringify
Here's author example:
var bundle = browserify()
.transform(stringify(['.hjs', '.html', '.whatever']))
.add('my_app_main.js');
If you really want to use require(), you may want to look at partialify:
my.txt:
Hello, world!
index.js:
alert( require( "my.txt" ) );
Where Browserify is configured:
var partialify = require( "partialify/custom" );
partialify.alsoAllow( "txt" );
bundle.add( "./index.js" );
bundle.transform( partialify );
Theoretically you will get a "Hello, world!" message in browser.
P.S. I haven't tried this myself.
Edit: note that this solution breaks NodeJS compatibility - it only works in browserified state, as NodeJS doesn't know how to require .txt files.

Resources