I'm relatively new to gulp and am using it as a taskrunner to concatenate and compile .js and sass/css files. Those aspects are currently working in a development environment.
What I'm confused about is a workflow issue. Right now my concatentated files are in these folders:
-css (myapp.css)
-js (myappconcat.js)
If I'm working locally, I don't want to minify these yet for debugging purposes (right?).
However, reading up on gulp, I see that build tasks are normally set up to minify the assets into a 'dist' folder for production. How do I manage this in my HTML files?
For example, in my development HTML file I would have CSS and js includes like so:
<link href="/css/myapp.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="/js/myappconcat.js"></script>
However, when I build my minified files to a 'dist' directory, I would have to change the paths in the includes above for every HTML file.
How does one go about managing a gulp build to a dist folder without having to change the paths in each include in the HTML? Similarly, when I minify for production, don't I also have to change the .js and CSS filenames in the HTML includes as well? Or should I be using minified files in development?
EDIT: Here's the basic site structure:
wwwroot
-.html files
- gulpfile.js
- package.json
/css
-main.css
/dist
/js
/scss
AND the gulpfile.js
// Required gulp modules
var gulp = require('gulp'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
maps = require('gulp-sourcemaps'),
del = require('del'),
jshint = require('gulp-jshint'),
stylish = require('jshint-stylish'),
gutil = require( 'gulp-util' ),
merge = require('merge-stream'),
imagemin = require('gulp-imagemin'),
cleanCSS = require('gulp-clean-css');
// error reporter in progress
var reportError = function( err ) {
gutil.beep();
var title = 'Error';
if( err.plugin === 'gulp-sass' ) {
title = 'SCSS Compilation Error';
}
var msg = '\n============================================\n\n';
msg += title += '\n\n';
msg += err.message + '\n\n';
msg += '============================================';
gutil.log( gutil.colors.red( msg ) );
if( err.plugin === 'gulp-sass' ) {
this.emit('end');
}
};
// Concatenate .js files with lint-js as the dependency
gulp.task("concatScripts", ["lint-js"], function() {
return gulp.src([
'js/*.js'
,'node_modules/jquery-placeholder/jquery.placeholder.js'
])
.pipe(maps.init())
.pipe(concat('zConcat.js'))
.pipe(maps.write('./'))
.pipe(gulp.dest('dist/js'));//write to separate dir than src otherwise
overwrites itself!
});
// Minify .js files with concatscripts as the dependency
gulp.task("minifyScripts", ["concatScripts"], function() {
return gulp.src("dist/js/zConcat.js")
.pipe(uglify())
.pipe(rename('zConcat.js'))
.pipe(gulp.dest('dist/js'));
});
// .js Linter for catching errors when any .js changes
gulp.task('lint-js', function () {
return gulp.src([
'js/*.js', // all custom .js
//'!_js/public/js/html5shiv.js', // ignore shiv
])
.pipe(jshint())
.pipe(jshint.reporter(stylish)); // color-coded line by line errors
});
// Compile sass files
gulp.task('compileSass', function() {
return gulp.src("scss/main.scss")
.pipe(maps.init())
.pipe(sass(
{
outputStyle: 'expanded'
}
).on( 'error', reportError) ) //sass.logError
.pipe(maps.write('./'))
.pipe(gulp.dest('css'));
});
// Minify CSS after compiling
gulp.task('minifyCSS', () => {
return gulp.src('css/*.css')
.pipe(maps.init())
.pipe(cleanCSS({compatibility: 'ie8'}))
.pipe(rename('main.min.css'))
.pipe(maps.write('./'))
.pipe(gulp.dest('css'));
});
// Watch and process SASS and .js file changes
gulp.task('watchFiles', function() {
gulp.watch(['scss/**/*.scss','scss/*.scss'], ['compileSass']);
gulp.watch( 'css/*.css', ['minifyCSS']);
gulp.watch('js/**/*.js', ['concatScripts']);
});
this might be late, but no one answered.
For me, I create two production files (or folders if the output is more than one file, with each folder containing a set of files). One is minified, and the other is not.
For development and testing purposes, I use the non-minified version. Once the product is ready for production, I retest but using the minified version, and typically this is the one I release.
So I write my scripts to produce two files (or file sets if I have more than a file to produce).
Hope this helps.
Related
I receive custom js and css script as a string through html form. This strings are then saved in files on filesystem. The question is how to minify those files every time they are generated/updated. I am using gulp and laravel elixir.
My first idea was to call exec("gulp something") but not sure how to configure gulp.
Requirments:
gulp-newer
minifyCss
gulp-uglify
First step:(install plugins)
minifyCss and gulp-uglify are used by laravel-elixir. You have to install gulp-newer by npm install gulp-newer --save-dev.
Second step:(define task)
You need to define different tasks for css and js.
CSS task
gulp.task('cssTask', function() {
return gulp.src(cssSrc)
.pipe(newer(cssDest))//compares the css source and css destination(css files)
.pipe(minifyCss())//minify css
.pipe(gulp.dest(cssDest));//save minified css in destination directory
});
Js task
gulp.task('jsTask', function() {
return gulp.src(jsSrc)
.pipe(newer(jsDest))//compares the js source and js destination(js files)
.pipe(uglify())//minify js
.pipe(gulp.dest(jsDest));//save minified js in destination directory
});
Third step:(define custom watch)
You should have a watch task which watches your source directories(cssSrc and jsSrc) and calls its related task.
gulp.task('custom', function() {//Watch task
gulp.watch(cssSrc, ['cssTask']);//watch your css source and call css task
gulp.watch(jsSrc, ['jsTask']);//watch your js source and call js task
});
Fourth step:(run custom watch)
Finally, you must run the custom task by gulp custom.
Conclusion:
Every time, when file is added to the source directory. Gulp will minify the file and store it in destination directory. This is tested locally and it works perfectly.
Completed Gulp file
var gulp = require('gulp');
var elixir = require('laravel-elixir');
var newer = require('gulp-newer');
var minifyCss = require('gulp-minify-css');
var uglify = require('gulp-uglify');
cssSrc = 'cssSrc/*.css';//Your css source directory
cssDest = 'cssDest';//Your css destination directory
jsSrc = 'jsSrc/*.js';//Your js source directory
jsDest = 'jsDest';//Your js destination directory
gulp.task('cssTask', function() {
return gulp.src(cssSrc)
.pipe(newer(cssDest))//compares the css source and css destination(css files)
.pipe(minifyCss())//minify css
.pipe(gulp.dest(cssDest));//save minified css in destination directory
});
gulp.task('jsTask', function() {
return gulp.src(jsSrc)
.pipe(newer(jsDest))//compares the js source and js destination(js files)
.pipe(uglify())//minify js
.pipe(gulp.dest(jsDest));//save minified js in destination directory
});
gulp.task('custom', function() {//Watch task
gulp.watch(cssSrc, ['cssTask']);//watch your css source and call css task
gulp.watch(jsSrc, ['jsTask']);//watch your js source and call js task
});
Edited after comment:
I would like something like this: gulp custom srcFile destFile.
For that situation, you need to install new plugin which is called yargs.
Installation:
You can install yargs by npm install yargs --save-dev and then you have to pass source directory and destination directory when custom task is called.
gulp custom --cssSrc=cssSource --cssDest=cssDestination --jsSrc=jsSource --jsDest=jsDestination
For example:
gulp custom --cssSrc=cssSrc/*.css --cssDest=cssDest --jsSrc=jsSrc/*.js --jsDest=jsDest
The completed Gulp file:
var gulp = require('gulp');
var elixir = require('laravel-elixir');
var newer = require('gulp-newer');
var minifyCss = require('gulp-minify-css');
var uglify = require('gulp-uglify');
var argv = require('yargs').argv;
cssSrc = argv.cssSrc;
cssDest = argv.cssDest;
jsSrc = argv.jsSrc;
jsDest = argv.jsDest;
gulp.task('cssTask', function() {
return gulp.src(cssSrc)
.pipe(newer(cssDest))
.pipe(minifyCss())
.pipe(gulp.dest(cssDest));
});
gulp.task('jsTask', function() {
return gulp.src(jsSrc)
.pipe(newer(jsDest))
.pipe(uglify())
.pipe(gulp.dest(jsDest));
});
gulp.task('custom', function() {
gulp.watch(cssSrc, ['cssTask']);
gulp.watch(jsSrc, ['jsTask']);
});
Note: Every time, the source directory or destination directory is changed, gulp task must be called again.
Use the below gulp modules.
https://www.npmjs.com/package/gulp-minify-css - Minify all your css files.
https://www.npmjs.com/package/gulp-concat-css - Merge all your css in to one file.
https://www.npmjs.com/package/gulp-uglify - Minigy all your JS files.
https://www.npmjs.com/package/gulp-sass - SASS
Refer this answer:
Gulp minify multiple js files to one
Below is sample Gulp File Snippet.
var gulp = require('gulp'),
sass = require('gulp-sass'),
autoprefixer = require('gulp-autoprefixer'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
imagemin = require('gulp-imagemin'),
rename = require('gulp-rename'),
clean = require('gulp-clean'),
concat = require('gulp-concat'),
notify = require('gulp-notify'),
cache = require('gulp-cache'),
livereload = require('gulp-livereload'),
lr = require('tiny-lr'),
server = lr();
// Clean
gulp.task('clean', function() {
return gulp.src(['css', 'js', 'img'], {
read: false
})
.pipe(clean());
});
gulp.task('styles', function() {
return gulp.src('sass/styles.scss')
.pipe(sass({
style: 'expanded'
}))
.pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
.pipe(gulp.dest('css'))
.pipe(notify({
message: 'Styles task complete'
}));
});
// Concatenate & Minify JS
gulp.task('scripts', function() {
return gulp.src('js/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('dist'))
.pipe(rename('all.min.js'))
.pipe(uglify())
.pipe(gulp.dest('dist'));
});
// Watch
gulp.task('watch', function() {
// Watch .scss files
gulp.watch('sass/**/*.scss', ['styles']);
// Watch .js files
gulp.watch('js/**/*.js', ['scripts']);
// Watch image files
gulp.watch('img/**/*', ['images']);
// Create LiveReload server
var server = livereload();
// Watch any files in dist/, reload on change
gulp.watch(['sass/**', 'js/**', 'img/**', '*.html']).on('change', function(file) {
server.changed(file.path);
});
});
gulp.task('default', ['styles', 'scripts', 'watch']);
At first place, you need to store the content in a new file. A good place for this is resources/assets/js:
$jsContent = $request->get('js_custom_content');
file_put_contents(base_path('resources/assets/js/custom.js'), $jsContent);
Ok, once created the javascript file, you need to tell to elixir to minify the custom script:
// it will look for resources/assets/js/custom.js
// and it will compress the output to public/assets/js/custom.min.js
mix.scripts(['custom.js'], 'public/assets/js/custom.min.js');
Optionally, you can version it. That means that everytime the script's content change, gulp will generate a new version in order to avoid browser's cache issues:
mix.version(['public/assets/js/custom.min.js']);
Finally, load the script in your view:
<script type="text/javascript" src="{{ url('assets/js/custom.min.js')) }}"></script>
Or with version:
<script type="text/javascript" src="{{ url(elixir('assets/js/custom.min.js')) }}"></script>
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'));
}
I'm a Gulp JS beginner. Currently I'm trying to compile some simple less code to CSS. My Gulp task should output a new CSS file for this but after I run the task, nothing happens. I've included the gulp-util module to try to debug the task execution but it doesn't show me any errors.
Here's my Gulp file:
// gulpfile.js
// --- INIT
var gulp = require('gulp'),
util = require('gulp-util'),
less = require('gulp-less'), // compiles less to CSS
minify = require('gulp-minify-css'), // minifies CSS
concat = require('gulp-concat'),
rename = require('gulp-rename'),
uglify = require('gulp-uglify'); // minifies JS
// Paths variables
var paths = {
'dev': {
'less': './laravel/public/assets/less/'
},
'assets': {
'css': './laravel/public/assets/css/ ',
'js': './laravel/public/assets/js/',
'vendor': './laravel/public/assets/bower_vendor/'
}
};
// --- TASKS
// Auth CSS
gulp.task('auth.css', function(){
return gulp.src(paths.dev.less + 'auth.less')
.pipe(less().on('error', util.log))
.pipe(gulp.dest(paths.assets.css))
.pipe(minify({keepSpecialComments:0}))
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(paths.assets.css));
});
// --- WATCH
// --- DEFAULT
gulp.task('default', ['auth.css']);
I'm using Laravel 4. This file lives in the root directory. I have changed the paths but that doesn't seem to work either. Any ideas?
Try removing the extra space at the end of your path.assets.css.
Just fixed. It seems, the path had to be something like: "./public/assets/css/". Now the file has been generated.
I am working with Gulp.js, and I am stumped trying to get gulp-sourcemaps to point all the way back at the original less files, after I do a minification step.
Since gulp-minify-css doesn't support sourcemaps, I am using postcss & csswring.
Ideally, I'd like to end up with:
ss.css (unminified)
ss.css.map (pointing from ss.css back to original .less files)
ss.min.css (minified)
ss.min.css.map (pointing from ss.min.css back to original .less files)
For now, I've stopped trying to output both the minified and non-minified versions, but even getting the minified version to point back to the original .less files doesn't seem to work.
Without doing a minification step, my .map file works great and looks like this:
{"version":3,"sources":["ss.less"],"names":[],"mappings":";AAEA;...
When I do the minification step, it changes the map to point the minified file back at the compiled CSS, not the original Less files:
{"version":3,"sources":["ss-min.css"],"names":[],"mappings":";AAEA;...
Here's my gulpfile.js:
var csswring = require('csswring'),
gulp = require('gulp'),
less = require('gulp-less'),
path = require('path'),
postcss = require('gulp-postcss'),
rename = require('gulp-rename'),
sourcemaps = require('gulp-sourcemaps');
var sourceLess = path.join(__dirname, 'app', 'assets', 'less');
var targetCss = path.join(__dirname, 'app', 'assets', 'css');
// Compile Less to CSS and then Minify, Include Sourcemaps
gulp.task('less-and-minify-css', function () {
return gulp.src(lessFiles)
.pipe(sourcemaps.init())
.pipe(less())
.pipe(rename({suffix: "-min"}))
.pipe(postcss([csswring]))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(targetCss));
});
As always, any thoughts appreciated!
I have experimented with using a filter to only rename the generated .css files and nothing else, but that doesn't seem to fix the core issue.
After more fiddling, I was able to get it to work with minification, although I still wasn't able to save the minified and non-minified versions in a single task.
The use of a function for the rename was required because just adding a suffix ends up with the map being named 'file.css.min.map' instead of 'file.min.css.map' which is what's required to get them to match up.
I added the gulpif to save time running the .less files through the csswring command.
gulp.task('less-css-and-minify', function () {
return gulp.src(lessFiles)
.pipe(sourcemaps.init())
.pipe(less())
.pipe(gulpif('**/*.css', postcss([csswring])))
.pipe(rename(function (path) {
if (path.extname === '.map') {
path.basename = path.basename.replace('.css', '.min.css');
}
if (path.extname === '.css') {
path.basename += '.min';
}
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(targetCss));
});
I have a simple gulpfile that loads a javascript object from a json file (to get paths based on environment), compiles my scss files, moves them to my public directory, and also moves any javascript files to the public directory.
So my assets in /app/Http/assets/js and scss
are compiled and moved to /public/assets/js and css
Here is my gulpfile.js:
var gulp = require('gulp');
var gutil = require('gulp-util');
var notify = require('gulp-notify');
var sass = require('gulp-sass');
var autoprefix = require('gulp-autoprefixer');
// Load the application config
var config = require('./env.config.json');
// Where do you store your Sass files?
var sassDir = 'app/Http/Assets/scss';
// Which directory should Sass compile to?
var targetCSSDir = config.assets_path + '/css';
// Where do you store your CoffeeScript files?
var jsDir = 'app/Http/Assets/js';
// Which directory should CoffeeScript compile to?
var targetJSDir = config.assets_path + '/js';
/** Tasks **/
// Compile Sass, autoprefix CSS3, and save to target CSS directory
gulp.task('css', function () {
return gulp.src(sassDir + '/**/*.scss')
.pipe(sass())
.pipe(autoprefix('last 10 version'))
.pipe(gulp.dest(targetCSSDir))
.pipe(notify('CSS minified'))
});
// Move Javascript
gulp.task('js', function () {
return gulp.src(jsDir + '/**/*.js')
.pipe(gulp.dest(targetJSDir))
});
// Keep an eye on Sass and Javascript files for changes...
gulp.task('watch', function () {
gulp.watch(sassDir + '/**/*.scss', ['css']);
gulp.watch(jsDir + '/**/*.js', ['js']);
});
// What tasks does running gulp trigger?
gulp.task('default', ['css', 'js', 'watch']);
This is working fine for my javascript. Also, when I run "gulp" the first time, it compiles all my scss files and moves them accordingly. However, the watch task is not working for my scss files. It DOES work for javascript files. What's really weird (to me) is that when I change my scss source to a specific file, the watch works. So,
gulp.task('css', function () {
return gulp.src(sassDir + '/**/app.scss')
.pipe(sass())
// and the rest is the same
will watch AND compile any changes to my app.scss file, but obviously not to any other scss files.
I have re-arranged and googled all I can. I don't understand why it won't work for watching scss.
EDIT: Strangely, it seems to be notify that is breaking the css watcher. When I comment it out like so:
gulp.task('css', function () {
return gulp.src(sassDir + '/**/*.scss')
.pipe(sass())
.pipe(autoprefix('last 10 version'))
.pipe(gulp.dest(targetCSSDir))
//.pipe(notify('CSS minified'))
});
everything works as expected.
Thanks in advance.