I have the code:
var gulp = require('gulp');
var webpack = require('webpack-stream');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
gulp.task('webpack', function() {
gulp.src('*/lib/*.coffee', { base: '.' })
.pipe(coffee({ bare: true }))
.pipe(concat('app.js'))
.pipe(webpack())
.pipe(gulp.dest('.'));
});
However, it doesn't work, when it reaches webpack(). How can I make it so that the content passed from concat() to webpack() works successfully?
I also assume that if I removed the concat() pipe, and went straight from coffee() to webpack(), then I'd end up with multiple files processed by webpack() rather than a single one, right?
I tried using coffee-loader for Webpack, but for some reason it outputs content with bare: false (when I look at the output file), even though in the actual package, it appears that it's hardcoded to output with bare: true. So that's why I'm using gulp-coffee instead.
Related
I want to uglify and combine my js files with gulp. Here is my code
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var pump = require('pump');
var gutil = require('gulp-util');
gutil.env.type = 'production';
gulp.task('uglify', function (cb) {
return gulp.src([
'pure/modernizr.js',
'pure/horizon.js'
])
.pipe(gutil.env.type === 'production' ? uglify() : gutil.noop())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest("ugly"));
});
var sourcemaps = require("gulp-sourcemaps");
var concat = require("gulp-concat-js");
gulp.task("concat", function () {
return gulp.src([
'ugly/modernizr.js',
'ugly/horizon.js'
])
.pipe(sourcemaps.init())
.pipe(concat({
"target": "concatenated.js", // Name to concatenate to
"entry": "./main.js" // Entrypoint for the application, main module
// The `./` part is important! The path is relative to
// whatever gulp decides is the base-path, in this
// example that is `./lib`
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest("pure/"));
});
I end up with some code enclosing my js files from obfuscator stating:
//// THIS FILE IS CONCATENATED WITH gulp-obfuscator-js
When I include this in code, it throws require is not defined, I surf around the web and found one similar question. But that answer is also not clear for me. I believe that I miss some small thing here, since I am new to gulp.
The issue here is I have used gulp-concat-js which obfuscate your js. I should have used gulp-concat. May help someone.
I would like to know how exactly can I manipulate the output of my Gulp plugin so, for example, no matter how many files are passed to the plugin, it will wrap the output with a string. Currently I cannot know when does the last file is done.
The super simplified example below will iterate on 3 files and will create a new file named output.js and in it there will be three times the string xxx (xxxxxxxxx).
I would like the plugin itself to wrap the contents so the output will
be: +xxxxxxxxx+.
How can I do this?
Thanks!
Gulpfile
var gulp = require('gulp');
var concat = require('gulp-concat');
var foo = require('./index');
gulp.task('default', function() {
gulp.src([a.html, b.html, c.html])
.pipe(foo())
.pipe(concat('output.js'))
.pipe(gulp.dest('./test/output'))
});
The most basic gulp plugin (index.js):
var through2 = require('through2'),
gutil = require('gulp-util');
var PLUGIN_NAME = 'foo';
module.exports = function( options ){
// through2.obj(fn) is a convenience wrapper around
// through2({ objectMode: true }, fn)
return through2.obj(function( file, enc, callback ){
file.contents = new Buffer( 'xxx' );
this.push(file);
callback();
});
}
I understand the files are currently simply returned modified, but what I don't understand is how to append text and return the concatenated result that I want, while keeping it OK with Gulp working standards.
The "real" plugin should actually wrap the files results with:
var foo = { FILES_CONTENT }
where FILES_CONTENT will actually be a a concatenated string of all the files:
"file_name" : "file_content",
"file_name" : "file_content",
...
I would make the following changes to your gulpfile.js:
var gulp = require('gulp');
var foo = require('./index.js');
gulp.task('default', function() {
return gulp.src(['a.html', 'b.html', 'c.html'])
.pipe(foo({fileName:'output.js', varName:'bar'}))
.pipe(gulp.dest('./test/output'))
});
Since your foo() plugin itself will concatenate all the files, there's no need to use gulp-concat at all. Instead your plugin should accept an option fileName that provides the name of the generated file. I've also added another option varName that will provide the name of the var in the output file.
I'll assume that a.html, b.html and c.html are simple HTML files, something like this:
<h1 class="header">a</h1>
As you've already realized you need to concat all the files in the plugin itself. That's not really difficult however and doesn't require a lot of code. Here's a index.js which does exactly that:
var through2 = require('through2'),
gutil = require('gulp-util'),
path = require('path'),
File = require('vinyl');
var PLUGIN_NAME = 'foo';
module.exports = function(options) {
var files = { };
var outputFile = null;
return through2.obj(function(file, enc, callback){
outputFile = outputFile || file;
var filePath = path.relative(file.base, file.path);
files[filePath] = file.contents.toString();
callback();
}, function(callback) {
outputFile = outputFile ? outputFile.clone() : new File();
outputFile.path = path.resolve(outputFile.base, options.fileName);
outputFile.contents = new Buffer(
'var ' + options.varName + ' = ' +
JSON.stringify(files, null, 2) + ';'
);
this.push(outputFile);
callback();
});
}
Since you want to output a key/value mapping from file names to file contents our transformFunction just stores both of those things in a regular JavaScript object files. None of the input files themselves are emitted. Their names and contents are just stored until we have all of them.
The only tricky part is making sure that we respect the .base property of each file as is customary for gulp plugins. This allows the user to provide a custom base folder using the base option in gulp.src().
Once all files have been processed through2 calls the flushFunction. In there we create our output file with the provided fileName (once again making sure we respect the .base property).
Creating the output file contents is then just a matter of serializing our files object using JSON.stringify() (which automatically takes care of any escaping that has to be done).
The resulting ./test/output/output.js will then look like this:
var bar = {
"a.html": "<h1 class=\"header\">a</h1>\n",
"b.html": "<h1 class=\"header\">b</h1>\n",
"c.html": "<h1 class=\"header\">c</h1>\n"
};
You should use the gulp pipeline technique (standard).
This means that you can use the gulp-insert package in order
to add the string xxx.
var insert = require('gulp-insert');
.pipe(insert.append('xxx')); // Appends 'xxx' to the contents of every file
You can also prepend, append and wrap with this package and it support of course the gulp standards.
So the full example will be:
var gulp = require('gulp');
var concat = require('gulp-concat');
var foo = require('./index');
var insert = require('gulp-insert');
gulp.task('default', function() {
gulp.src([a.html, b.html, c.html])
.pipe(foo()
.pipe(insert.append('xxx'))
.pipe(concat('output.js'))
.pipe(gulp.dest('./test/output'))
});
I'm using gulp with browserify and tsify. This has been working quite well. Then I decided to add ng-annotate using browserify-ngannotate.
I've added the ng-annotate browserify transform but it seems that if tsify is added as a plugin the ng-annotate transform is never called.
If I remove the tsify plugin then ng-annote gets called. I've played around and switched around the plugin/transform registration. Am I missing something here, or should I go and log an issue at browserify/tsify?
var browserify = require('browserify');
var browserSyncConfig = require('../config').browserSync;
var browserSync = require('browser-sync').get(browserSyncConfig.instance);
var watchify = require('watchify');
var tsify = require('tsify');
var ngAnnotate = require('browserify-ngannotate');
var mergeStream = require('merge-stream');
var bundleLogger = require('../util/bundleLogger');
var gulp = require('gulp');
var handleErrors = require('../util/handleErrors');
var source = require('vinyl-source-stream');
var config = require('../config').browserify;
var _ = require('lodash');
var browserifyTask = function (devMode) {
var browserifyThis = function (bundleConfig) {
if (devMode) {
// Add watchify args and debug (sourcemaps) option
_.extend(bundleConfig, watchify.args, {debug: true});
// A watchify require/external bug that prevents proper recompiling,
// so (for now) we'll ignore these options during development. Running
// `gulp browserify` directly will properly require and externalize.
bundleConfig = _.omit(bundleConfig, ['external', 'require']);
}
var b = browserify(bundleConfig);
if (bundleConfig.tsify) {
b = b.plugin(tsify, {
noImplicitAny: false,
target: 'ES5',
noExternalResolve: false,
module: 'commonjs',
removeComments: false
});
}
if (bundleConfig.ngAnnotate) {
b = b.transform(ngAnnotate);
}
var bundle = function () {
// Log when bundling starts
bundleLogger.start(bundleConfig.outputName);
return b
.bundle()
// Report compile errors
.on('error', handleErrors)
// Use vinyl-source-stream to make the
// stream gulp compatible. Specify the
// desired output filename here.
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.pipe(browserSync.stream());
};
if (devMode) {
// Wrap with watchify and rebundle on changes
b = watchify(b, {
poll: true
});
// Rebundle on update
b.on('update', bundle);
bundleLogger.watch(bundleConfig.outputName);
} else {
// Sort out shared dependencies.
// b.require exposes modules externally
if (bundleConfig.require) b.require(bundleConfig.require);
// b.external excludes modules from the bundle, and expects
// they'll be available externally
if (bundleConfig.external) b.external(bundleConfig.external);
}
return bundle();
};
// Start bundling with Browserify for each bundleConfig specified
return mergeStream.apply(gulp, _.map(config.bundleConfigs, browserifyThis));
};
gulp.task('browserify', function () {
return browserifyTask()
});
// Exporting the task so we can call it directly in our watch task, with the 'devMode' option
module.exports = browserifyTask;
You can solve it by specify extensions in ng-annotate options.
bundler.transform(ngAnnotate, { ext: ['.ts', '.js'] });
I realized I had this problem too, when I added uglifyify to the bundle transforms to produce minified builds.
An important aspect of my solution is that the missing, explicit $inject statements, that ng-annotate should have inserted, doesn't matter until the code is actually minified. Luckily, UglifyJS2, which does the actual minification in uglifyify, got support for handling ng-annotate's ngInject comments in version 2.4.9 (in January, 2014).
So, the solution that worked for me was to install uglifyify:
npm install --save-dev uglifyify
and add the following uglifyify transform to the Browserify bundle:
b.transform({
global: true,
mangle: false,
comments: true,
compress: {
angular: true
}
}, 'uglifyify');
This will make UglifyJS2 insert the appropriate $inject statements into your code before it is minified.
So, to summarize, I did not have a solution for only using ng-annotate, but my solution will add the necessary $inject statements before the code is minified, which is what matters in most cases.
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'),
]})
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