Can browserify require a vinyl file generated in gulp? - javascript

I've just started using gulp and browserify and I need some help with this problem:
I'm using a lib called ng-autobootstrap to generate a browserify compatible file, which is later on required in the main script. Here's my autobootstrap task:
gulp.task "autobootstrap", ->
gulp.src("source/**/*.{coffee,js}",
read: false
base: "source"
)
.pipe(ngAutoBootstrap(
moduleTypes:
animation:
path: "**/animations/*.{coffee,js}",
constant:
path: "**/constants/*.{coffee,js}",
controller:
path: "**/controllers/*.{coffee,js}",
directive:
path: "**/directives/*.{coffee,js}",
factory:
path: "**/factories/*.{coffee,js}",
filter:
path: "**/filters/*.{coffee,js}",
provider:
path: "**/providers/*.{coffee,js}",
service:
path: "**/services/*.{coffee,js}",
value:
path: "**/values/*.{coffee,js}",
# config modules are pulled in like this:
# app.config(require("./path/to-config"))
config:
path: "**/*-config.{coffee,js}"
))
If I add .pipe(gulp.dest("./source/")), it will create a bootstrap.js file in the source directory, but this is not exactly what I want, I would rather keep that directory clean. As far as I understand, up to now I have a vinyl file in memory, with the following content:
'use strict';
module.exports = function(app) {
// Controllers
app.controller('AppController', require('./controllers/app-controller'));
app.controller('UsersController', require('./controllers/users-controller'));
// ... and so on
};
Let's suppose the source/js/main.js file looks like this:
app = angular.module("app");
require("./bootstrap")(app); // this is the file generated by ng-autobootstrap
And a simple browserify task which creates the build/bundle.js file:
browserify = require('browserify')
gulp = require('gulp')
source = require('vinyl-source-stream')
gulp.task 'browserify', ->
browserify('./source/main.js')
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('./build/'))
Now, if I modify the autobootstrap to write the file to disc first, then run browserify, this is all fine, the ./bootstrap file will be there. But is there a way to avoid writing to disc? Something like adding a vinyl file to browserify's search tree?

Use b.require to make a file available from outside of the bundle. And in order to use the vinyl streams, that Gulp uses/emits, with Browserify; we make a small inline transform using through2.obj to emit only the contents.
A note on using b.require is that you need to b.exclude so that module-deps doesn't try to resolve it in the node_modules directories, etc. See issues #908 and #1106 for more information.
var gulp = require('gulp');
var through = require('through2');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
gulp.task('browserify-bundle', function() {
return browserify('./test/main.js')
// We need to exclude the required module so `module-deps` doesn't try to resolve it in the `node_modules` directories, etc
// Suggested here: https://github.com/substack/node-browserify/issues/908#issuecomment-74909062
// See also: https://github.com/substack/node-browserify/issues/1106
.exclude('some-func')
// Then add in the module to the bundle
.require(
gulp.src('./test/hidden-some-func.js')
// Any plugins here....
// .pipe(ngAutoBootstrap(..)
//
// Then convert it to a object stream with only the `contents` for browserify to consume
.pipe(through.obj(function(chunk, env, cb) {
if (chunk.isStream()) {
self.emit('error', new gutil.PluginError(PLUGIN_NAME, 'Cannot operate on stream'));
}
else if (chunk.isBuffer()) {
this.push(chunk.contents);
}
// "call callback when the transform operation is complete."
cb();
})),
{
// Dependency name to inject
expose: 'some-func',
// So that relative requires will be resolvable
basedir: './test/'
}
)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('dest'));
});

Related

Bundle .js and .css dependecies from package.json with gulp

I'm trying to convert an old project that uses Bower + gulp (+ npm) into something similar, which doesn't use Bower but keeps most of Gulp.
I'm stuck with reproducing the equivalent of wiredep, ie, picking all the relevant .js and .css from third party dependencies (which now are moved from Bower to package.json), to use them for either HTML injection or bundling all .js/.css into a single file.
Before, it was doing this, using a mix of wiredep and inject:
gulp.task('inject-html', ['compile-styles'], function () {
$.util.log('injecting JavaScript and CSS into the html files');
var injectStyles = gulp.src(config.outputCss, { read: false });
var injectScripts = gulp.src(config.js, { read: false });
var wiredepOptions = config.getWiredepDefaultOptions();
var injectOptions = {
ignorePath: ['src', '.tmp'], addRootSlash: false,
};
var wiredep = require('wiredep').stream;
return gulp.src(config.html)
.pipe(wiredep(wiredepOptions))
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(gulp.dest(config.srcDir), {overwrite: true});
});
Now, I've managed to do this for the .js files:
gulp.task('bundle-deps', function () {
var deps = Object.keys(packageJson.dependencies)
.map(module => `node_modules/${module}/**/*.js`);
// set up the browserify instance on a task basis
var b = browserify({
entries: './package.json',
debug: true
});
return b.bundle()
.pipe(source('genemap-lib.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true})) // debug info for the browser
.pipe(uglify())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./dist/js/'));
});
This works in building a single dependency .js. That's not like the injection above, but I'd be fine with it.
However, I can't find any way to do the same for the .css files, because this:
gulp.task('bundle-deps-css', function () {
var deps = Object.keys(packageJson.dependencies);
var depsCss = deps.map(module => `node_modules/${module}/**/*.css`);
return gulp.src( depsCss )
.pipe(concatCss("genemap-lib.css"))
.pipe(gulp.dest('dist/styles/'));
});
picks up some */demo/demo.css and then I get the error that it has a syntax error.
I'm thinking that the above methods are wrong, selecting all .js/.css is too dumb, there should be a way to select the library-exported files, not all that can be found in its directory (ie, the gulp equivalent of wiredep).
But how to do it? Is it possible with Gulp? Should I migrate to something like webpack? And Yarn too?

handlebars:compile - Cannot read property 'filter' of undefined use

I've been searching around but there seemed to be no situation similar to mine so thought I'd post to ask. I want to run the handlebars task in Gruntfile.js with grunt handlebars to compile a templates.js in my source folder (www) but it doesn't fire up with this error shown:
Warning: Cannot read property 'filter' of undefined Use
Here's my script for the handlebars task in grunt file:
// Create the tasks
grunt.initConfig({
config: config,
handlebars: {
// Compiles the handlebar templates into templates.js
compile: {
options: {
amd: true,
processName: function (filepath) {
var pieces = filepath.split('/');
return pieces[pieces.length - 1].split('.')[0];
}
},
// Specify location of handlebar templates
www: ['<%= config.www %>/html/{,*/}*.handlebars'],
dest: '<%= config.www %>/js/templates.js'
}
}
});
Here's opening script of grunt file and the config object, before grunt.initConfig :
module.exports = (function () {
'use strict';
return function (grunt) {
require('load-grunt-tasks')(grunt); // Several tasks to run using grunt-contrib-xx plugins
// Config object
var config = {
www: 'www', // all source files in one directory
};
.. // grunt.initConfig
};
});
Couldn't figure out what goes wrong here since I don't even define a property/term filter and that's the only error received. Any thoughts would be appreciated.
So I will write what I did to resolve this which might be of use to you.
I simply changed the www property specifically to src, as referred to in the first code block, for the handlebars task in grunt file to fire up. Existing handlebars which are markups are sourced a.k.a. src and to compile the templates.js in your specified destination.
Note: handlebars file itself should end with unspecified file type (.handlebars). Depending on your own set up, noting this will save you lots of time afterwards.
Now run below and you shall see the templates.js found in the dest folder.
grunt handlebars

gulp-rev creates a directory inside the destination directory

First of all, I would like to say that Gulp (for me) is creating more problems instead of solving them.
I wrote a gulpfile that concat some CSS files and put them inside a directory. The code for this task is the following:
var config = {
mainDir: 'app/assets'
};
config.stylesFiles = [
'bower_resources/admin-lte/dist/css/AdminLTE.min.css',
'bower_resources/admin-lte/dist/css/skins/_all-skins.min.css',
'css/app.css'
];
....
gulp.task('styles', function() {
return gulp
.src(config.stylesFiles, { cwd: config.mainDir })
.pipe(sourcemaps.init())
.pipe(concat('theme.css'))
.pipe(sourcemaps.write('../build/css'))
.pipe(gulp.dest('public/css/'))
.on('end', function() { gutil.log('Styles copied') });
});
It is very simple and works perfectly.
But, I would like to version this generated file. So I wrote a specific task to do it:
....
config.manifestFolder = process.cwd() + '/public/build';
gulp.task('versionCSS', function() {
return gulp
.src(['css/theme.css'], { cwd: 'public' })
.pipe(rev())
.pipe(gulp.dest('public/build/css'))
.pipe(rev.manifest(
{
base: config.manifestFolder,
cwd: config.manifestFolder,
merge: true
}
))
.pipe(gulp.dest(config.manifestFolder))
.on('end', function() { gutil.log('CSS files versioned') });
});
The problem is: when Gulp is going to run this task, it creates a folder inside the destination folder.
After running Gulp, I get this structure:
- public
- build
- css (destination folder for the versioned file)
- css (folder created by Gulp)
- versioned file that should be in the parent folder
- css
- concatenated file without version
I really don't know what to do anymore. I've already set the cwd and base options for the dest and src functions, changed the destinations, synchronized the tasks, etc. Nothing solves this stupid behavior.

Gulp using wiredep for bower dependencies: output different path

I'm using Gulp with wiredep. The output I get is not the right path to my files. I'd like to change the output of that path accordingly.
Current path:
<script src="../bower_components/angular/angular.js"></script>
Wanted outcome:
<script src="./vendors/angular.js"></script>
Current gulp task:
gulp.task('index', function() {
var target = gulp.src(files.app_files.target);
var sources = gulp.src(files.app_files.sources, {
read: false
});
// {caseSensitive: true }
return target
.pipe(inject(sources, {
ignorePath: 'app'
}))
.pipe(wiredep())
.pipe(gulp.dest('dist'));
});
wiredep is born to wire bower dependencies in your html.
Anyway you can set a programmatica acces to js like this
Programmatic Access
You can run wiredep without manipulating any files.
require('wiredep')();
...returns...
{
js: [
'paths/to/your/js/files.js',
'in/their/order/of/dependency.js'
],
css: [
'paths/to/your/css/files.css'
],
// etc.
}
as you can find in the doc
As advice, in dev phase there is nothing wrong using bower_dependencies as your "repo". In build phase, when you prepare for prduction environment you can use useref in combination with wiredep and then move your builded file where you want it

Webstorm debugging with source maps from Browserify and Typescript

My project is a Laravel site, and I have the public folder renamed to "html". So my public files look like:
html
--js
----main.ts
And html is technically the root of the site for debugging purposes.
Using browserify, I have now generated some source maps for bundle.js, which have paths for main.ts. The problem is that they are pointing to the full path:
"html/js/main.ts"
Usually, I can run configurations to the html folder and catch breakpoints.
http://myapp.app:8000 ->> project>html
But this is not hitting breakpoints, since the html folder doesn't really exist in this setup. What's strange is that I can set break points in Chrome tools and it works. How can I set up Webstorm so it will hit break points in the html folder?
EDIT:
I am using the following gist for my source maps.
/**
* Browserify Typescript with sourcemaps that Webstorm can use.
* The other secret ingredient is to map the source directory to the
* remote directory through Webstorm's "Edit Configurations" dialog.
*/
'use strict';
var gulp = require('gulp'),
browserify = require('browserify'),
tsify = require('tsify'),
sourcemaps = require('gulp-sourcemaps'),
buffer = require('vinyl-buffer'),
source = require('vinyl-source-stream');
var config = {
client: {
outDir: './public/scripts',
out: 'app.js',
options: {
browserify: {
entries: './src/client/main.ts',
extensions: ['.ts'],
debug: true
},
tsify: {
target: 'ES5',
removeComments: true
}
}
}
};
gulp.task('client', function () {
return browserify(config.client.options.browserify)
.plugin(tsify, config.client.options.tsify)
.bundle()
.on('error', function (err) {
console.log(err.message);
})
.pipe(source(config.client.out))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('./', {includeContent: false, sourceRoot: '/scripts'}))
.pipe(gulp.dest(config.client.outDir));
});
I fixed it in Webstorm. The correct remote url for the html folder in run configurations is:
http://myapp.app:8000/js/html
Pretty weird, but Webstorm thinks that /js/html is a folder and that the source files are inside there.
EDIT 1 :Let me edit this answer. It turns out that the snippet above wasn't giving me all of the source maps. When inspecting the map file, the sources were being listed as js files and not ts files, which meant that the debugger wouldn't catch break points.
Here is the working gulp task, which watches any Typescript file for changes (as long as it's a dependency of main.ts and triggers browserify and the new sourcemaps. It requires the tsify plugin.
'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: ['./html/js/main.ts'],
debug: true
};
var opts = assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts));
gulp.task('bundle', 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
b.plugin('tsify')
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({includeContent: false, sourceRoot: './'})) // writes .map file
.pipe(gulp.dest('./html/js'));
}

Categories