Using Gulp and minified CSS/JS - html

I recently started using Gulp to autoprefix, minifycss and minify my JS. Right now, all the files that get autoprefixed, minified are sitting in a dist folder. Is there a way I can point my html file to these minified versions without manually retyping the following :
<script src="js/custom.js"></script>
to :
<script src="dist/custom.min.js"></script>
back and forth?
Right now, when I develop, I edit about 5 to 10 css and JS files but when I edit them, it's obviously in the unminified, unautoprefixed version. I'm sure that's not how developers do it so I'm guessing there's a step that I'm missing...

You should look at using source maps. From that article:
Basically it's a way to map a combined/minified file back to an unbuilt state. When you build for production, along with minifying and combining your JavaScript files, you generate a source map which holds information about your original files. When you query a certain line and column number in your generated JavaScript you can do a lookup in the source map which returns the original location. Developer tools (currently WebKit nightly builds, Google Chrome, or Firefox 23+) can parse the source map automatically and make it appear as though you're running unminified and uncombined files.
gulp-sourcemaps is what you will need to use. You don't mention which gulp plugins you are using, but there's a good chance that they have support for source maps.
Here's a simple example of how you would use it:
var gulp = require('gulp');
var minify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
gulp.task('minify', function() {
gulp.src('src/*.js')
.pipe(sourcemaps.init()) // Initialize the source maps.
.pipe(minify()) // Do your minification, concatenation, etc.
.pipe(sourcemaps.write()) // Write the source maps.
.pipe(gulp.dest('dist')); // Write the minified files.
});
Just make sure that the original unminified files are also being server by your web server so that the browser can download them.
This also has the added advantage that when you are testing your webpage at development time, you're actually running the minified code that you will end up deploying.

You can try the gulp-replace plugin, write a task, something like this:
var replace = require('gulp-replace')
gulp.task('adoptDist', function() {
return gulp.src(paths.dest + '/www/**/*.html', { base: paths.dest })
.pipe(replace(/src="js\/(.+?)\.js"/g, function(match, $1) {
return 'src="dist/' + $1 + '.min.js"'
}))
.pipe(gulp.dest(paths.dest))
});

Related

How to load sourcemaps with uglifyjs2 and Ionic?

For my Ionic app, I am using some gulp tasks to minify the Javascript code. Uglifyjs2 minifies the code:
gulp.task('uglify', () => {
gulp.src(paths.uglify)
.pipe(uglify('app.min.js', {
outSourceMap: true
}))
.pipe(gulp.dest('./www/dist/js-uglify'));
});
This generates the files
www
| dist
| | js-uglify
| | | app.min.js
| | | app.min.js.map
app.min.js thus ends with //# sourceMappingURL=app.min.js.map
In my index.html I have the following reference:
<script src="dist/js-uglify/app.min.js"></script>
When I build and run my app via ionic run the file app.min.js is loaded. However, the sourcemap is missing. Chrome seems to be set up properly (the option Enable JavaScript source maps is set).
How can I tackle this problem? Should the Network list of transmitted files contain an entry for the source map? Can I somehow manually force Chrome to load the map?
I am not familiar with uglifyjs, but a quick look at some ionic software that uses it online suggests that maybe you did not configure your flags correctly. It looks like you are meant to run
uglifyjs [input files] [options]
Using the option --source-map output.js.map.
Ok, another thing which may be relevant: according to the gruntjs GitHub, that sourceMappingURL flag no longer works.
Version 3.x introduced changes to configuring source maps
...
sourceMappingURL - This is calculated automatically now sourceMapPrefix - No longer necessary for the above reason ...
sourceMap - Only accepts a Boolean value. Generates a map with a default name for you sourceMapRoot - The location of your sources is now calculated for you when sourceMap is set to true but you can set manual source root if needed
So maybe instead of using sourceMappingURL you should just set the boolean to true? Hope this helps!
gulp-uglifyjs is deprecated. It's possible that your sourcemaps are not being created properly.
Current best practice is to use the following modules to uglify/concat/sourcemap your code:
gulp-uglify
gulp-concat
gulp-sourcemaps
Example:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var sourcemaps = require('gulp-sourcemaps');
gulp.task('build-js', function () {
return gulp.src('app/**/*.js')
.pipe(sourcemaps.init())
.pipe(uglify())
.pipe(concat('app.min.js'))
.pipe(sourcemaps.write('.', { includeContent: false, sourceRoot: '../app' }))
.pipe(gulp.dest('dist'));
});
See this related answer for an explanation of why these gulp modules work better.
Also, in Chrome, the app.min.js.map file does not show up in the Network tab. You'll know if your sourcemaps have been loaded if they show up in the Sources tab in an orange colored folder.

Rebuild all files if template changes

I'm using gulp to convert markdown files to HTML, and using the gulp-watch plugin (not the gulp.watch API function) to rebuild files if they change. Works great!
gulp.task('markdown', function () {
gulp.src('src/**/*.md')
.pipe(watch('src/**/*.md'))
.pipe(markdown())
.pipe(template('templates/md.tpl'))
.pipe(gulp.dest('dist'));
});
The problem is that the pipeline src is the markdown files, but within the pipeline I also reference a template file. If that template changes, all the markdown files need to be rebuilt. Is there a way to express that dependency in gulp/gulp-watch?
I tried using gulp.watch (the API function) to watch the template and run the 'markdown' task if it changes ...
gulp.watch('templates/md.tpl', ['markdown']);
... but that didn't work. Nothing happens. I assume having gulp-watch in the pipeline prevents it from doing anything.
I guess I could create a two tasks, one with gulp-watch and one without, and use the one without to force a full rebuild. I'd rather not, because then it becomes an ongoing problem to keep the two in sync.
Is there a better way?
I guess I could create a two tasks, one with gulp-watch and one without, and use the one without to force a full rebuild. I'd rather not, because then it becomes an ongoing problem to keep the two in sync.
Remember, gulp is just JavaScript.
Simply write a function that constructs the stream with or without the watch() step depending on a parameter that you pass. The gulp-if plugin let's you write something like this in a very concise way (although it's not necessary and could be done without it).
Here's how I would do it:
var gulpIf = require('gulp-if');
function processMarkdown(opts) {
gulp.src('src/**/*.md')
.pipe(gulpIf(opts.watch, watch('src/**/*.md')))
.pipe(markdown())
.pipe(template('templates/md.tpl'))
.pipe(gulp.dest('dist'));
}
gulp.task('markdown', function() {
processMarkdown({watch: true});
watch('templates/md.tpl', function() {
processMarkdown({watch: false});
});
});
You can specify gulp src as an array, too:
gulp.src(['src/**/*.md', 'templates/md.tpl'])

VS 2015 Use Gulp to Compile Less

I am trying to set up a similar process to what Web Essentials offered in the old visual studio in the newest one. For those of you who aren't familiar with how that worked, the process was:
File Setup:
a.less
a.css
a.min.css
a.css.map
b.less
b.css
b.min.css
b.css.map
So basically when you open a.less and start editing it, it would automatically check out a.css, a.min.css, and a.css.map as well. Then when you save, it would recompile the 3 sub files as well as saving the less file.
I am able to replicate this by writing a separate task for each file like so:
gulp.task('checkout', function () {
return gulp.src('Styles/brands.css')
.pipe(tfs());
});
gulp.task('less', ['checkout'], function () {
del('Styles/brands.css');
return gulp.src('Styles/brands.less')
.pipe(less())
.pipe(gulp.dest('Styles'));
});
This uses gulp-tfs-checkout to checkout the sub file, and then the less to compile. This works 100% how I expect it to. I can set up a watch to watch the less task and everything will work great. The only problem is, how do I expand this to handle all my less files in that folder? I could write separate checkout and compile tasks for each file, but that's not really ideal.
I am used to writing projects where saving any less file compiles and concats all of them into a single or a couple files, but this is a work project and for multiple reasons I need to keep the css files separate as they are now. We use visual studio's bundling, but its an older project and people have referenced the css files randomly outside of the bundling process so it would be a pretty big/risky task to change that.
I don't know how to watch many files, but only change the current one if that makes sense.
gulp.task('less', function () {
return gulp.src('Styles/*.less') //watch all of my files
.pipe(tfs())//checkout only the css file for the less file that was changed here somehow
.pipe(less()) //compile only the css file that was changed
.pipe(gulp.dest('Styles'));
});
I am fairly used to grunt and gulp, but like I said I generally do things in bulk on my project. I'm not sure how to do this when I want to watch all the files, but only change 1
Why don't you create all those tasks per each file dynamically? You can read the contents of the folder where your less files are with fs.readdirSync and then if the file is a less file you create for each the task 'checkout' + filename and then 'less' + filename.
Being dynamically you will not have any problems when you create a new less file or when you remove one.

Inline sourcemap (generated with gulp-sourcemaps) not working

This is a bit of a weird one:
I've got a gulp task that looks like this:
gulp.task('less', function () {
gulp.src('./less/main.less')
.pipe(sourcemaps.init())
.pipe(less({
plugins: [cleancss]
}))
.pipe(sourcemaps.write()) // will write the source maps to ./public/assets/css-dist/maps
.pipe(gulp.dest(paths.public + 'css/dist'));
});
I'm running this task from inside a play 1.3 project, and it generates the base64-encoded inline sourcemap, as expected, but when I load it up in chrome, all of the styles are mapping to line 1 of main.css, indicating that something is wrong.
Now, here's where it gets weird: if I run this same task, pointing at copies of the same files, in another project with an identical directory structure, just running under plain-ol' apache, it works exactly as expected. The output files appear exactly the same.
Does anyone have any insight as to why this would be?
FWIW, an extremely similar scenario plays out when minifying and concatenating my js, using gulp-uglify and gulp-concat
Try see if you can visualize the difference/mappings via this visualizer tool. If both compiled files are exactly the same between the two projects then it's likely due to the different ways you are serving/accessing the files? With the 2nd project did you also try to view the sourcemap via Chrome?
Just to clarify, not only are you writing an inline sourcemap, you're also embedding your sources so everything is within the compiled .css file, the external original source files are not the referenced source(sourceRoot will be /source/).

Simple HTML Preprocessor

Is there a simple HTML preprocessor available to use for existing HTML code, that I won't need to modify my existing html to conform with preprocessors syntax?
I'm developing a mobile app with a few pages built with html, however i've started having the problem of having to update each page for when making changes to similiar content (header, footer etc) I don't want to duplicate content and have mismatches, rather i'd like to use a preprocessor that has an include method (something like how php does it), so that I can include these similiar contents.
I've looked at stuff like HAML & Jade, but it seems they have a strict syntax you need to follow with indents and the sort or editing html to include pipes on each line, else things wont compile.
Like I said I have existing html I would just like to cut & paste my HTML into different files, include them and stick with that workflow as I think it's the simplest.
But if anyone has any other ideas how I can tackle my situation that is welcomed too.
I guess since your requirement is to only include files that you don't need a full blown template system . You could take a look at gulp-include which is a gulp plugin to include files. Using gulp has the advantage that gulp comes with a watch feature to watch the file system for changes - whenever a change is detected a task can be triggered.
An example how your gulpfile.js could look like
var gulp = require('gulp');
var include = require('gulp-include');
gulp.task('template', function() {
return gulp
.src('*.html')
.pipe(include())
.pipe(gulp.dest('dist'))
});
gulp.task('dev', function() {
gulp.watch('*.html', ['template']);
});
gulp.task('default', ['template']);
This gulpfile registers a 'template' task that takes all html files and processes the file's contents with the gulp-include plugin. The template task is registed as default gulp task. So if you invoke gulp without any command line args then the template task is run. The gulp 'dev' task allows you to run gulp dev from the command line that watches all html files for changes and triggers the template task whenever a html file changes.
The gulp include plugin scans your html files for something like
= include relative/path/to/file.html
and includes 'file.html' contents.
The include syntax is quite well documented on the gulp-include web site.