Browserify + Remapify (Gulp workflow) - node.js

I've successfully got Browserify to compile my JavaScript entry files, but I want to utilise the Remapify plugin so as to not have to specify the full relative path upon requiring a module every time.
For example:
require('components/tabs.js')
Rather than:
require('../../components/tabs/tabs.js').
But I cannot get the shorter module references to map to the corresponding file... "Error: Cannot find module [specified_ref] from [file]".
Have I misconfigured Remapify, or is there something wrong with my wider Browserify setup? I am new to Broswerify and Gulp having previously used Require.js and Grunt. Any help would be greatly appreciated. Please let me know if you need any more information about my setup.
If alternatively you can recommend an alternative Gulp task file that will do all of this, thereby throwing my current task out the window, by all means. I wasn't able to find many Browserify + Remapify examples.
Directory Structure
I have my modules (components) in the following directory: './src/components', so for example: './src/components/tabs/tabs.js'.
I am requiring these modules in a JS file for a given page of the app, which are in: './src/pages', so for example, './src/pages/portfolio/portfolio.js'.
Gulp Browserify Task
var gulp = require('gulp');
var config = require('../config');
var browserify = require('browserify');
var remapify = require('remapify');
var source = require('vinyl-source-stream');
var glob = require('glob');
var browserSync = require('browser-sync');
gulp.task('browserify', function(){
var entries = glob.sync(config.src.pages + '/**/*.js');
return browserify({
entries: entries,
debug: true
})
// (Remapify:)
.plugin(remapify, [{ src: config.src.components + '/**/*.js', expose: 'components', cwd: config.srcDir }])
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest(config.build.js))
.pipe(browserSync.reload({ stream: true }));
});
Page.js
'use strict';
var tabs = require('components/tabs.js'); // (Doesn't work, but I want it to)
// var tabs = require('../../components/tabs/tabs.js'); // (Does work)

Remapify has all sorts of problems. I suggest giving my pathmodify plugin a shot.
For your situation usage would look something like:
var pathmod = require('pathmodify');
// ...
.plugin(pathmod(), {mods: [
pathmod.mod.dir('components', '/path/to/src/components'),
]})

Related

Modify gulp file to run customized browserify command

I would like to use gulp to run a custom browserify command whenever a js file (function.js) is modified.
The browserify command that I want to run is;
$ browserify function.js --standalone function > bundle.js
I am using this gulpfile.js as sample.
https://github.com/gulpjs/gulp/blob/master/docs/recipes/fast-browserify-builds-with-watchify.md
How do I modify this gulpfile to run the customized browserify command?
'use strict';
var watchify = require('watchify');
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var gutil = require('gulp-util');
var sourcemaps = require('gulp-sourcemaps');
var assign = require('lodash.assign');
// add custom browserify options here
var customOpts = {
entries: ['./src/index.js'],
debug: true
};
var opts = assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts));
// add transformations here
// i.e. b.transform(coffeeify);
gulp.task('js', bundle); // so you can run `gulp js` to build the file
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
function bundle() {
return b.bundle()
// log errors if they happen
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
// optional, remove if you dont want sourcemaps
.pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file
// Add transformation tasks to the pipeline here.
.pipe(sourcemaps.write('./')) // writes .map file
.pipe(gulp.dest('./dist'));
}
I am using node.js v6.9 on webstorm.
The command you want to run is;
$ browserify function.js --standalone function > bundle.js
Based on this, the modified code is;
// add custom browserify options here
var customOpts = {
entries: ['./function.js'],
standalone: 'function',
};
Simply add one more property to customOpts for the --standalone parameter. The rest of the code remains the same.

grunt + mochaTest: Change working directory?

I`m trying to implement testing for my nodejs-project with grunt-mocha-test and have issues with different/incorrect paths.
Like I saw it elsewhere, I want to get all dependecies by just requiring my server.js.
gruntfile.js
mochaTest: {
test: {
options: {
reporter: 'spec',
require: 'app/server.js'
},
src: ['app/test/**/*.js']
}
}
My current project structure looks like this
gruntfile.js
app/server.js
app/models/..
app/controllers/..
app/tests/..
users.controller.test.js
var userCtl = require('../controllers/users.controller');
describe("return5", function () {
it("should return 5", function () {
var result = userCtl.return5(null, null);
expect(result).toBe(5);
});
});
users.controller.js
var mongoose = require('mongoose');
var User = mongoose.model('User'); // <- Mocha crash: Schema hasn't been registered for model "User".
..
In my server.js I use:
..
// config.js: https://github.com/meanjs/mean/blob/master/config/config.js
config.getGlobbedFiles('./models/**/*.js').forEach(function (path) {
require(path); // never called with mochaTest
});
..
console.log(process.cwd()); // "C:\path\project" (missing /app)
..
So the cwd is different to what it should be.
Can someone please help me getting around this issue?
I will clarify the title as soon as I know what I`m doing wrong.
Thank you.
The confusion is due to the difference between module paths and filesystem paths.
When you do require("./blah"), the . is interpreted to mean "start with the path of the current module". Since this is relative to the module you are currently in, it will resolve to different values depending on where the module is located.
When you run process.cwd() this is returning the current working directory of the process. This does not change from module to module. It changes when your code calls process.chdir(). Also, when you perform filesystem operations that use ., this is interpreted relative to process.cwd().
So that you get C:\path\project from process.cwd() is not surprising since this is where you'd typically run Grunt (i.e. at the top level of your project). What you can do if you want paths relative to a module is use __dirname. For instance, this code reads files from a foo subdirectory in the same location where the module that contains this code is located:
var path = require("path");
var fs = require("fs");
var subdir = path.join(__dirname, "foo");
var foofiles = fs.readdirSync(subdir);

Gulp, livereload, jade

Need help.
I use gulp-conect and it livereload method. But if I build a few template in time, get a lot of page refresh. Is any solution, I want to build few templates with single page refresh?
So, I reproduce the problem you have and came accross this working solution.
First, lets check gulp plugins you need:
gulp-jade
gulp-livereload
optional: gulp-load-plugins
In case you need some of them go to:
http://gulpjs.com/plugins/
Search for them and install them.
Strategy: I created a gulp task called live that will check your *.jade files, and as you are working on a certain file & saving it, gulp will compile it into html and refresh the browser.
In order to accomplish that, we define a function called compileAndRefresh that will take the file returned by the watcher. It will compile that file into html and the refesh the browser (test with livereload plugin for chrome).
Notes:
I always use gulp-load-plugin to load plugins, so thats whay I use plugins.jad and plugins.livereload.
This will only compile files that are saved and while you have the task live exucting on the command line. Will not compile other files that are not in use. In order to accomplish that, you need to define a task that compiles all files, not only the ones that have been changed.
Assume .jade files in /jade and html output to /html
So, here is the gulpfile.js:
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
gulp.task('webserver', function() {
gulp.src('./html')
.pipe(plugins.webserver({
livereload: true
}));
gulp.watch('./jade/*.jade', function(event) {
compileAndRefresh(event.path);
});
});
function compileAndRefresh(file) {
gulp.src(file)
.pipe(plugins.jade({
}))
.pipe(gulp.dest('./html'))
}
Post edit notes:
Removed liveReload call from compileAndRefresh (webserver will do that).
Use gulp-server plugin insted of gulp-connect, as they suggest on their repository: "New plugin based on connect 3 using the gulp.src() API. Written in plain javascript. https://github.com/schickling/gulp-webserver"
Something you can do is to watch only files that changes, and then apply a function only to those files that have been changed, something like this:
gulp.task('live', function() {
gulp.watch('templates/folder', function(event) {
refresh_templates(event.path);
});
});
function refresh_templates(file) {
return
gulp.src(file)
.pipe(plugins.embedlr())
.pipe(plugins.livereload());
}
PS: this is not a working example, and I dont know if you are using embedlr, but the point, is that you can watch, and use a callback to call another function with the files that are changing, and the manipulate only those files. Also, I supposed that your goal is to refresh the templates for your browser, but you manipulate as you like, save them on dest or do whatever you want.
Key point here is to show how to manipulate file that changes: callback of watch + custom function.
var jadeTask = function(path) {
path = path || loc.jade + '/*.jade';
if (/source/.test(path)) {
path = loc.jade + '/**/*.jade';
}
return gulp.src(path)
.pipe(changed(loc.markup, {extension: '.html'}))
.pipe(jade({
locals : json_array,
pretty : true
}))
.pipe(gulp.dest(loc.markup))
.pipe(connect.reload());
}
First install required plugins
gulp
express
gulp-jade
connect-livereload
tiny-lr
connect
then write the code
var gulp = require('gulp');
var express = require('express');
var path = require('path');
var connect = require("connect");
var jade = require('gulp-jade');
var app = express();
gulp.task('express', function() {
app.use(require('connect-livereload')({port: 8002}));
app.use(express.static(path.join(__dirname, '/dist')));
app.listen(8000);
});
var tinylr;
gulp.task('livereload', function() {
tinylr = require('tiny-lr')();
tinylr.listen(8002);
});
function notifyLiveReload(event) {
var fileName = require('path').relative(__dirname, event.path);
tinylr.changed({
body: {
files: [fileName]
}
});
}
gulp.task('jade', function(){
gulp.src('src/*.jade')
.pipe(jade())
.pipe(gulp.dest('dist'))
});
gulp.task('watch', function() {
gulp.watch('dist/*.html', notifyLiveReload);
gulp.watch('src/*.jade', ['jade']);
});
gulp.task('default', ['livereload', 'express', 'watch', 'jade'], function() {
});
find the example here at GitHub

How can I use factor-bundle with browserify programmatically?

I want to use factor-bundle to find common dependencies for my browserify entry points and save them out into a single common bundle:
https://www.npmjs.org/package/factor-bundle
The factor-bundle documentation makes it seem very easy to do on the command line, but I want to do it programmatically and I'm struggling to get my head around it.
My current script is this (I'm using reactify to transform react's jsx files too):
var browserify = require('browserify');
var factor = require('factor-bundle')
var glob = require('glob');
glob('static/js/'/**/*.{js,jsx}', function (err, files) {
var bundle = browserify({
debug: true
});
files.forEach(function(f) {
bundle.add('./' + f);
});
bundle.transform(require('reactify'));
// factor-bundle code goes here?
var dest = fs.createWriteStream('./static/js/build/common.js');
var stream = bundle.bundle().pipe(dest);
});
I'm trying to figure out how to use factor-bundle as a plugin, and specify the desired output file for each of the input files (ie each entry in files)
This answer is pretty late, so it's likely you've either already found a solution or a work around for this question. I'm answering this as it's quite similar to my question.
I was able to get this working by using factor-bundle as a browserify plugin. I haven't tested your specific code, but the pattern should be the same:
var fs = require('fs'),
browserify = require('browserify'),
factor = require('factor-bundle');
var bundle = browserify({
entries: ['x.js', 'y.js', 'z.js'],
debug: true
});
// Group common dependencies
// -o outputs the entry files without the common dependencies
bundle.plugin('factor-bundle', {
o: ['./static/js/build/x.js',
'./static/js/build/y.js',
'./static/js/build/z.js']
});
// Create Write Stream
var dest = fs.createWriteStream('./static/js/build/common.js');
// Bundle
var stream = bundle.bundle().pipe(dest);
The factor-bundle plugin takes output options o which need to have the same indexes as the entry files.
Unfortunately, I haven't figured out how to do anything else with these files after this point because I can't seem to access factor-bundle's stream event. So for minification etc, it might need to be done also via a browserify plugin.
I have created grunt-reactify to allow you to have a bundle file for a JSX file, in order to make it easier to work with modular React components.
All what you have to do is to specify a parent destination folder and the source files:
grunt.initConfig({
reactify: {
'tmp': 'test/**/*.jsx'
},
})

How to ignore libraries in browserify programmatic api

Assume the below code is found in bundler.js and tracing entry.js leads to var B = require('backbone'); (Backbone is a dependency installed as declared in package.json).
var browserify = require('browserify');
var bundle = new browserify();
bundle.add('entry.js');
bundle.bundle({
noParse: ['backbone']
});
Executing this bundler yields a stream that contains the original backbone source. Based on browserify's command line options I expected it to skip backbone alltogether. Reading through the source, I expected perhaps the following would work:
var browserify = require('browserify');
var bundle = new browserify({
noParse: ['backbone']
});
bundle.add('entry.js');
bundle.bundle();
Though backbone source still appears in the stream output.
Is it possible to use --noparse=FILE as a configuration option in this application of the api?
As you can see from here the --noparse option provided on the command line is passed to the browserify({ }) call.
So in order to tell browserify to not parse jquery and three.js you have to pass the full path to your jquery and three.js files.
Example:
browserify({
noParse: [
require.resolve('./vendor/jquery'),
require.resolve('./vendor/three')
]
})
.require(require.resolve('./entry.js'), { entry: true })
.bundle();
var browserify = require("browserify")
browserify({entries: ['./src/client/app.js']})
.ignore('jquery')
That would make browserify ignore jquery, and then jquery can be added on index.html directly.

Resources