Why won't browser-sync update my browser? - node.js

Awe, why won't browser sync update chrome. =[ I'm using gulp to run browser sync which appears to be hosting correctly. I've set up the server like this in my gulp file:
var gulp = require('gulp');
var browser = require('browser-sync');
var reload = browser.reload;
gulp.task('webserver', function() {
browser({
server:{
baseDir: './'
}
});
});
gulp.task('reload', function(){reload();});
I run the webserver task in webstorm and I get a new chrome tab with a little message saying "Connected to Browser Sync". Awesome. I also get this in the output window.
[18:47:45] Using gulpfile ...\gulpfile.js
[18:47:45] Starting 'webserver'...
[18:47:45] Finished 'webserver' after 27 ms
[BS] Access URLs:
-------------------------------------
Local: http://localhost:3000
External: http://192.168.1.17:3000
-------------------------------------
UI: http://localhost:3001
UI External: http://192.168.1.17:3001
-------------------------------------
[BS] Serving files from: ./
Everything looks great. Then I change some HTML in my index.html and run the reload task. I get this output:
[19:02:55] Using gulpfile ...\gulpfile.js
[19:02:55] Starting 'reload'...
[19:02:55] Finished 'reload' after 121 μs
Process finished with exit code 0
But the browser isn't updates with my latest content. I've tried to boil this down to the most basic code that should work, but I can't get it to update the browser. =[ Am I missing anything that would keep this from working?

TL;DR
I do believe your answer is how you are watching the files, and then calling load. So basically, if you are using sass or less, or typescript, etc. You need to have your browsersync task:
watch for those files first, then execute their task to transpile (compile) to your .css, .js, etc...
Once it detects the changes in the .css, .js, .html files (which will occur after they transpiler tasks converts them to those files), have it reload the browser.
But whether or not you are using those, you still watch all the folders locations and file extensions. This is done by putting all the locations you are watching into an array, and watching the array of files.
NOTE: Browsersync has a separate .watch() from gulp's watch. Using browsersyncs watch function instead of gulp will see new files, where as gulps watch command does not. See example's below.
I apologize for providing such a needlessly verbose response, but I use gulp-cli (gulp 4) w/ multiple task files and external config), and haven't used gulp 3 in a while, so I will try to port it over in a single task to gulp 3.
Some examples
I am providing both versions since gulp 4 may soon be released. And I will just copy and paste mine, and slightly modify it. And that means I will be using the multiple task files version.
So here is an overview of the two versions that I will provide:
The one I use, which is: gulp 4 w/ multiple task files and an external config
The gulpfile
The external task
The external config
I will also include an example sass and typescript config to show globbing with browser-sync's watch task
The gulpfile with the browser-sync task that I will try to port to gulp 3
1. Gulp 4 w/ multiple task files and external config
I will provide some notes in each file as I do in each of my own. And I will provide install instructions if interested, as I do in each of mine as well. This is mostly for copy and paste reasons. And also I will provide the config for sass and typescript, since it is out of scope for the answer, I will not be providing the task files.
And here is a brief overview of the gulp folder structure to help clarify:
| -- Project-Folder/
| | -- gulp/
| | | -- tasks/
| | | ' -- browser-sync.js
| | ' -- config.js
| ' -- gulpfile.js
The gulpfile
gulpfile.js
// =========================================================
// Project: PROJECT-TITLE
//
// NOTES: Using Gulp 4, in order to use, please uninstall gulp 3 globally and locally, and install gulp 4 both globally and locally
// Dependencies: ---
// Global: npm install -g gulpjs/gulp.git#4.0 browser-sync
// Local: npm install --save-dev gulpjs/gulp.git#4.0 browser-sync gulp-load-plugins
// =========================================================
// ------------------------------------------------ Requires
var gulp = require('gulp'),
config = require('./gulp/config'),
plugins = require('gulp-load-plugins')();
// --------------------function to get tasks from gulp/tasks
function getTask(task) {
return require('./gulp/tasks/' + task)(gulp, plugins);
}
// ---------------------------------------------- Gulp Tasks
gulp.task('sass' , getTask( 'sass' ));
gulp.task('ts' , getTask( 'typescript' ));
gulp.task('sync' , getTask( 'browsersync' ));
// --------------------------------------- Default Gulp Task
gulp.task('default', gulp.series(
gulp.parallel('sass', 'ts'), 'sync')
);
The external task file
browser-sync.js
// =========================================================
// Gulp Task: browsersync
// NOTE: Using gulp v4
// Description: Sync sass, typescript, html, and browser
// using an external config, or modify src and config options
// npm install --save-dev browser-sync gulp-typescript gulpjs/gulp.git#4.0
// Options: node-sass gulp-sass || gulp-ruby-sass
// =========================================================
var config = require( '../config.js' );
var browserSync = require( 'browser-sync' ).create();
module.exports = function( gulp, plugins ) {
return function () {
var stream =
// -------------------------------------------- Start Task
browserSync.init( config.browsersync.opts );
browserSync.watch( config.sass.src, gulp.series( 'sass' ) );
browserSync.watch( config.typescript.src, gulp.series( 'ts' ) );
browserSync.watch( config.browsersync.watch ).on( 'change', browserSync.reload );
// ---------------------------------------------- End Task
return stream;
};
};
The external config
NOTE: These configs are easily added into the tasks file if this seems unnecessary. I am only providing so that I can easily copy and paste some tasks from my own project.
// =========================================================
// Project: PROJECT-TITLE
// =========================================================
// ------------------------------------------ Export Configs
module.exports = {
production: false,
// --------------------------------------------- browsersync
browsersync: {
opts: {
server: './src/',
// proxy: 'localhost:3000',
port: 8000
},
watch: [
'./src/assets/styles/css/**/*.css',
'./src/assets/scripts/js/**/*.js',
'./src/**/*.html'
]
},
// ---------------------------------------------------- sass
sass: {
src: [
"./src/assets/styles/sass/**/*.{scss,sass}"
],
opts: { },
outputName: 'main.css',
dest: './src/assets/styles/css/'
},
// ---------------------------------------------- typescript
typescript: {
src: [
'./src/assets/scripts/ts/**/*.ts'
],
dest: './src/assets/scripts/js',
opts: {
noImplicitAny: true,
}
}
}
Gulp 3 version
NOTE: In the config section, I will only be putting the sass and typescript src folders with extensions, and will leave the rest empty as they are not pertinent to this example.
gulpfile.js
// =========================================================
// Project: PROJECT-TITLE
//
// NOTES: Using Gulp 4, in order to use, please uninstall gulp 3 globally and locally, and install gulp 4 both globally and locally
// Dependencies: ---
// Global: npm install -g gulpjs/gulp.git#4.0 browser-sync
// Local: npm install --save-dev gulpjs/gulp.git#4.0 browser-sync gulp-load-plugins
// =========================================================
// ------------------------------------------------ Requires
var gulp = require( 'gulp' ),
sass = require( 'gulp-sass' ),
ts = require( 'gulp-typescript' )
browsersync = require( 'browser-sync' ).create();
// -------------------------------------------------- Config
var config = {
browsersync = {
opts: {
server: './src/',
// proxy: 'localhost:3000',
port: 8000
},
watch: [
'./src/assets/styles/css/**/*.css',
'./src/assets/scripts/js/**/*.js',
'./src/**/*.html'
]
},
sass = { src: './src/assets/styles/sass/**/*.{scss,sass}', ... },
ts = { src: './src/assets/scripts/ts/**/*.ts', ... }
}
// ---------------------------------------------- Gulp Tasks
gulp.task( 'sass', function() {
// task code here
});
gulp.task( 'ts', function() {
// task code here
});
gulp.task('browsersync', [ 'sass', 'ts' ], function() {
browserSync.init( config.browsersync.opts );
// Transpile your preprocessors to their .css, .js, .html versions first
browserSync.watch( config.sass.src, [ 'sass' ] );
browserSync.watch( config.typescript.src, [ 'ts' ] );
// Then under watch, watch all of the locations in an array glob
// such as in the config object at the top of this file.
// Once the preprocessors change to their .css, .js, .html
// counterparts, that will trigger the reload
browserSync.watch( config.browsersync.watch ).on( 'change', browserSync.reload );
});
// --------------------------------------- Default Gulp Task
gulp.task( 'default', [ 'browsersync' ] );
Again, sorry for the very long and detailed response. Just tried for clarity. I hope it helps you and anyone else in the future.

Related

Gulp Command Run Never Finish

I have bought template MaterialPro from wrappixel website. After I got the template package already, I have followed getting started installation from document attached with template as the following:
Install Node.js From https://nodejs.org/en/download/
Open terminal navigating to material-pro/
Install npm: npm install --global npm#latest
Install yarn: npm install --global yarn
Install gulp: npm install --global gulp-cli
Copy gulp: gulp copy
The gulpfile.js inside root template is like this:
//gulpfile.js
console.time("Loading plugins"); //start measuring
const gulp = require('gulp'),
minifyCSS = require('gulp-clean-css'),
uglify = require('gulp-uglify'),
rename = require("gulp-rename"),
sass = require('gulp-sass'),
npmDist = require('gulp-npm-dist');
console.timeEnd('Loading plugins');
const sassFiles = 'src/assets/scss/*.scss',
cssDest = 'dist/css/';
//compile scss into css
function style() {
return gulp.src(sassFiles)
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest(cssDest));
}
//This is for the minify css
async function minifycss() {
return gulp.src(['dist/css/*.css', '!dist/css/**/*.min.css'])
.pipe(rename({
suffix: '.min'
}))
.pipe(minifyCSS())
.pipe(gulp.dest(cssDest));
}
// This is for the minifyjs
async function minifyjs() {
return gulp.src(['dist/js/custom.js','dist/js/app.js', '!dist/js/custom.min.js', '!dist/js/app.min.js'] )
.pipe(rename({
suffix: '.min'
}))
.pipe(uglify())
.pipe(gulp.dest('dist/js'));
}
// Copy dependencies to ./public/libs/
async function copy() {
gulp.src(npmDist(), {
base: './node_modules'
})
.pipe(gulp.dest('./src/assets/libs'));
};
async function watch() {
gulp.watch(['src/assets/scss/**/*.scss'], style);
gulp.watch(['dist/css/style.css'], minifycss);
gulp.watch(['dist/js/**/*.js', '!dist/js/**/*.min.js'], minifyjs);
}
gulp.task('default', watch);
exports.style = style;
exports.minifycss = minifycss;
exports.minifyjs = minifyjs;
exports.copy = copy;
exports.watch = watch;
After all, I made some changes to the template scss file, and run gulp command. At this point, the gulp command run never finished unitl now with output on terminal like this
Loading plugins: 539.410ms
[17:01:03] Using gulpfile ~/Documents/documentation/materialpro-bootstrap-latest/material-pro/gulpfile.js
[17:01:03] Starting 'default'...
[17:01:03] Finished 'default' after 18 ms
What was going wrong with this? Please kindly help, thanks.
P.S: Pls apologized if my question is incomplete or something, if I will try to add some more detail if suggested.
Your gulp code is fine. Made some change on your scss or js file it will show some changes.
Exaplantion
Your default command is gulp.task('default', watch);
when you run gulp it starts to watch your scss, css, js code. If there is new change it will execute the command.
Suggestion. Use like this.
async function watch() {
gulp.watch(['src/assets/scss/**/*.scss'], style, minifycss);
gulp.watch(['dist/js/**/*.js', '!dist/js/**/*.min.js'], minifyjs);
}

gulp can't find module source-map

I'm having an issue with sourcemaps in gulp: when I try to implement gulp-sourcemaps directly through a pipe, but also when I try to feed it in via webpack, which if I've understood correctly, has sourcemaps by default, I keep getting the same confusing error:
Error: Cannot find module 'source-map'
I can see the #gulp-sourcemaps folder in my node_modules, which contains within it an identity-map folder containing a bunch more node_modules including the source-map module in question, so I think everything is hooked up as it should be. That being said, I'm new to gulp, so I might be missing something really obvious.
Can anyone offer me some guidance on how to help gulp find the module?
// package vars
const pkg = require("./package.json");
// gulp
const gulp = require("gulp");
const gulpIf = require("gulp-if");
// webpack
const webpack_config = require("./webpack.config");
// load all plugins in "devDependencies" into the variable $
const $ = require("gulp-load-plugins")({
pattern: ["*"],
scope: ["devDependencies"]
});
// ...
gulp.task("sass", function() {
return gulp
.src(pkg.paths.app.scss + "**/*.scss")
.pipe($.sourcemaps.init())
.pipe($.sass())
.pipe($.autoprefixer())
.pipe($.sourcemaps.write("./maps"))
.pipe(gulp.dest(pkg.paths.app.css))
.pipe(
$.browserSync.reload({
stream: true
})
);
});
// ...
gulp.task("webpack", function() {
return gulp
.src(pkg.paths.app.js + "**/*.js")
.pipe($.webpack(webpack_config))
.pipe(gulp.dest(pkg.paths.public.js));
});
// ...

Inconsistent Results with Running Gulp from Visual Studio on Post Build

I'm running gulp 3.9.0 and calling some gulp commands from Visual Studio 2013. The flow is such that whenever I build in VS, gulp should clean my temporary and output files, then after a successful build, compile my javascript assets into one file.
The problem is that, I've noticed that after running "gulp build", sometimes my assets are not generated at all. This even happens on the command line. After running "gulp clean" (which removes the output), I have to run "gulp build" twice just to see the output materialize. It's as if gulp is failing silently. Not sure if this is an issue with Node running on Windows or if I have misconfigured something.
Note that VS is responsible for compiling all TypeScript files into a single .js in the \output folder.
Apologies in advanced if there is a better way to do what I'm trying to do. Still a gulp/node newbie.
VS Pre-Build:
gulp clean
VS Post-Build:
gulp build
gulpfile.js:
var gulp = require('gulp');
var del = require('del');
var concat = require('gulp-concat');
var ngAnnotate = require('gulp-ng-annotate');
var uglify = require('gulp-uglify');
var templateCache = require('gulp-angular-templatecache');
var concatCss = require('gulp-concat-css');
var minifyCss = require('gulp-minify-css');
gulp.task("cleanOutdatedLibraries", function(){
del("./Libs/*");
del(['./myapp.js', './myapp.min.js', './myapp.css'])
});
gulp.task("cleanTemporaryFiles", function(){
del("./output/*");
});
/** Run gulp clean on prebuild */
gulp.task('clean', ["cleanOutdatedLibraries", "cleanTemporaryFiles"])
gulp.task('copyNewestLibraries', function(){
var bowerFiles = ['angular/angular.min.js',
'angular/angular.js',
'angular/angular.min.js.map',
'angular-ui-router/release/angular-ui-router.min.js',
'angular-local-storage/dist/angular-local-storage.min.js',
'jquery/dist/jquery.min.js',
'jquery/dist/jquery.min.map',
'lodash/lodash.min.js',
'angular-resource/angular-resource.min.js',
'angular-resource/angular-resource.min.js.map',
'momentjs/min/moment.min.js',
'angular-loading-bar/src/loading-bar.js',
'ngDialog/js/ngDialog.min.js'];
gulp.src(bowerFiles, {cwd: "./bower_components/"})
.pipe(gulp.dest('./Libs'));
});
gulp.task('copyThirdPartyLibraries', function(){
var thirdPartyFiles = ['jquery-ui.min.js',
'angular-sanitize.min.js'];
gulp.src(thirdPartyFiles, {cwd: "./_thirdparty/"})
.pipe(gulp.dest('./Libs'));
});
/** Merge all Angular JS HTML templates into a cache */
gulp.task('mergeHtmlTemplatesIntoAngularCache', function(){
gulp.src('app/**/*.html')
.pipe(templateCache("templates.js", {
module: "myapp"
}))
.pipe(gulp.dest('./output/'));
});
gulp.task('produceMinfiedApp', function(){
gulp.src(['app/**/*.js', 'output/typescripts.js'])
.pipe(concat('bundle.min.js'))
.pipe(ngAnnotate())
.pipe(uglify())
.pipe(gulp.dest('./output/'));
gulp.src(['output/bundle.min.js', 'output/templates.js'])
.pipe(concat('myapp.min.js'))
.pipe(gulp.dest('./'));
});
gulp.task('produceApp', function(){
gulp.src(['app/**/*.js', 'output/typescripts.js'])
.pipe(concat('bundle.js'))
.pipe(ngAnnotate())
.pipe(gulp.dest('./output/'));
gulp.src(['output/bundle.js', 'output/templates.js'])
.pipe(concat('myapp.js'))
.pipe(gulp.dest('./'));
});
gulp.task('mergeStyles', function(){
gulp.src(['Styles/**/*.css'])
.pipe(concat('styles.css'))
.pipe(gulp.dest("./output/"));
gulp.src(['app/**/*.css'])
.pipe(concat('app.css'))
.pipe(gulp.dest("./output/"));
gulp.src(['output/styles.css', 'output/app.css'])
.pipe(concatCss("./myapp.css"))
.pipe(minifyCss({compatibility: 'ie10'}))
.pipe(gulp.dest('./'));
});
/** Run gulp build on post build */
gulp.task('build', ["copyNewestLibraries",
"copyThirdPartyLibraries",
"mergeHtmlTemplatesIntoAngularCache",
"produceMinfiedApp",
"produceApp",
"mergeStyles"]);
/** Run gulp build on post build */
gulp.task('build', ["copyNewestLibraries",
"copyThirdPartyLibraries",
"mergeHtmlTemplatesIntoAngularCache",
"produceMinfiedApp",
"produceApp",
"mergeStyles"]);
These tasks (copyNewestLibraries, produceApp, etc.) run asynchronously, in no particular order. E.g. produceApp may finish before copyNewestLibraries, which is probably not what you want.
See How to run Gulp tasks sequentially one after the other for more info.

Importing Sass through npm

Currently in our Sass files we have something like the following:
#import "../../node_modules/some-module/sass/app";
This is bad, because we're not actually sure of the path: it could be ../node_modules, it could be ../../../../../node_modules, because of how npm installs stuff.
Is there a way in Sass that we can search up until we find node_modules? Or even a proper way of including Sass through npm?
If you are looking for a handy answer in 2017 and are using Webpack, this was the easiest I found.
Suppose your module path is like:
node_modules/some-module/sass/app
Then in your main scss file you can use:
#import "~some-module/sass/app";
Tilde operator shall resolve any import as a module.
As Oncle Tom mentioned, the new version of Sass has this new importer option, where every "import" you do on your Sass file will go first through this method. That means that you can then modify the actual url of this method.
I've used require.resolve to locate the actual module entry file.
Have a look at my gulp task and see if it helps you:
'use strict';
var path = require('path'),
gulp = require('gulp'),
sass = require('gulp-sass');
var aliases = {};
/**
* Will look for .scss|sass files inside the node_modules folder
*/
function npmModule(url, file, done) {
// check if the path was already found and cached
if(aliases[url]) {
return done({ file:aliases[url] });
}
// look for modules installed through npm
try {
var newPath = path.relative('./css', require.resolve(url));
aliases[url] = newPath; // cache this request
return done({ file:newPath });
} catch(e) {
// if your module could not be found, just return the original url
aliases[url] = url;
return done({ file:url });
}
}
gulp.task("style", function() {
return gulp.src('./css/app.scss')
.pipe(sass({ importer:npmModule }))
.pipe(gulp.dest('./css'));
});
Now let's say you installed inuit-normalize using node. You can simply "require" it on your Sass file:
#import "inuit-normalize";
I hope that helps you and others. Because adding relative paths is always a pain in the ass :)
You can add another includePaths to your render options.
Plain example
Snippet based on example from Oncle Tom.
var options = {
file: './sample.scss',
includePaths: [
path.join(__dirname, 'bower_components'), // bower
path.join(__dirname, 'node_modules') // npm
]
};
sass.render(options, function(err, result){
console.log(result.css.toString());
});
That should do. You can include the files from package using #import "my-cool-package/super-grid
Webpack and scss-loader example
{
test: /\.scss$/,
loader: 'style!css!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap=true&sourceMapContents=true&includePaths[]=./node_modules'
},
Notice the last argument, includePaths has to be array. Keep in mind to use right format
You can use a Sass importer function to do so. Cf. https://github.com/sass/node-sass#importer--v200.
The following example illustrates node-sass#3.0.0 with node#0.12.2:
Install the bower dependency:
$ bower install sass-mq
$ npm install sass/node-sass#3.0.0-pre
The Sass file:
#import 'sass-mq/mq';
body {
#include mq($from: mobile) {
color: red;
}
#include mq($until: tablet) {
color: blue;
}
}
The node renderer file:
'use strict';
var sass = require('node-sass');
var path = require('path');
var fs = require('fs');
var options = {
file: './sample.scss',
importer: function bowerModule(url, file, done){
var bowerComponent = url.split(path.sep)[0];
if (bowerComponent !== url) {
fs.access(path.join(__dirname, 'bower_components', bowerComponent), fs.R_OK, function(err){
if (err) {
return done({ file: url });
}
var newUrl = path.join(__dirname, 'bower_components', url);
done({ file: newUrl });
})
}
else {
done({ file: url });
}
}
};
sass.render(options, function(err, result){
if (err) {
console.error(err);
return;
}
console.log(result.css.toString());
});
This one is simple and not recursive. The require.resolve function could help to deal with the tree – or wait until npm#3.0.0 to benefit from the flat dependency tree.
I made the sass-npm module specifically for this.
npm install sass-npm
In your SASS:
// Since node_modules/npm-module-name/style.scss exists, this will be imported.
#import "npm-module-name";
// Since just-a-sass-file isn't an installed npm module, it will be imported as a regular SCSS file.
#import "just-a-sass-file";
I normally use gulp-sass (which has the same 'importer' option as regular SASS)
var gulp = require('gulp'),
sass = require('gulp-sass'),
sassNpm = require('sass-npm')();
Then, in your .pipe(sass()), add the importer as an option:
.pipe(sass({
paths: ['public/scss'],
importer: sassNpm.importer,
}))
For dart-sass and commandline user at 2022, just use the --load-path option:
$ npx sass --load-path=node_modules
Important: the whole node_modules folder contains so much, just set it launch extremely slow in watch mode. Your should only set your package paths, eg:
$npx sass -w --load-path=node_modules/foo --load-path=node_modules/bar/scss
From offical docuumentation of Sass, adding ~ to imports should do the job.
However, for some reason it did'nt work for me, and sass compiler still complains that the module cannot be found.
Hence, I tried another method which worked for me without any issues. Here's the solution:
If you are compiling sass files directly from CLI try this:
sass src/main.scss dist/main.css --load-path=node_modules
If you are using npm and/or webpack for compiling sass files, add something like this to the scripts of package.json:
"scripts": {
...
"build": "sass src/main.scss dist/main.css --load-path=node_modules",
...
}
Then Run:
npm run build
Finally, import your modules like this:
#import "some-module/sass/app";
To wrap it up, adding --load-path=node_modules flag solved the issue permanently. For more information you can check:
sass --help

Using Gulp to build requireJS project - gulp-requirejs

I am trying to use gulp-requirejs to build a demo project. I expect result to be a single file with all js dependencies and template included. Here is my gulpfile.js
var gulp = require('gulp');
var rjs = require('gulp-requirejs');
var paths = {
scripts: ['app/**/*.js'],
images: 'app/img/**/*'
};
gulp.task('requirejsBuild', function() {
rjs({
name: 'main',
baseUrl: './app',
out: 'result.js'
})
.pipe(gulp.dest('app/dist'));
});
// The default task (called when you run `gulp` from cli)
gulp.task('default', ['requirejsBuild']);
The above build file works with no error, but the result.js only contains the content of main.js and config.js. All the view files, jquery, underscore, backbone is not included.
How can I configure gulp-requirejs to put every js template into one js file?
If it is not the right way to go, can you please suggest other method?
Edit
config.js
require.config({
paths: {
"almond": "/bower_components/almond/almond",
"underscore": "/bower_components/lodash/dist/lodash.underscore",
"jquery": "/bower_components/jquery/dist/jquery",
"backbone": "/bower_components/backbone/backbone",
"text":"/bower_components/requirejs-text/text",
"book": "./model-book"
}
});
main.js
// Break out the application running from the configuration definition to
// assist with testing.
require(["config"], function() {
// Kick off the application.
require(["app", "router"], function(app, Router) {
// Define your master router on the application namespace and trigger all
// navigation from this instance.
app.router = new Router();
// Trigger the initial route and enable HTML5 History API support, set the
// root folder to '/' by default. Change in app.js.
Backbone.history.start({ pushState: false, root: '/' });
});
});
The output is just a combination this two files, which is not what I expected.
gulp-requirejs has been blacklisted by the gulp folks. They see the RequireJS optimizer as its own build system, incompatible with gulp. I don't know much about that, but I did find an alternative in amd-optimize that worked for me.
npm install amd-optimize --save-dev
Then in your gulpfile:
var amdOptimize = require('amd-optimize');
var concat = require('gulp-concat');
gulp.task('bundle', function ()
{
return gulp.src('**/*.js')
.pipe(amdOptimize('main'))
.pipe(concat('main-bundle.js'))
.pipe(gulp.dest('dist'));
});
The output of amdOptimize is a stream which contains the dependencies of the primary module (main in the above example) in an order that resolves correctly when loaded. These files are then concatenated together via concat into a single file main-bundle.js before being written into the dist folder.
You could also minify this file and perform other transformations as needed.
As an aside, in my case I was compiling TypeScript into AMD modules for bundling. Thinking this through further I realized that when bundling everything I don't need the asynchronous loading provided by AMD/RequireJS. I am going to experiment with having TypeScript compile CommonJS modules instead, then bundling them using webpack or browserify, both of which seem to have good support within gulp.
UPDATE
My previous answer always reported taskReady even if requirejs reported an error. I reconsidered this approach and added error logging. Also I try to fail the build completely as described here gulp-jshint: How to fail the build? because a silent fail really eats your time.
See updated code below.
Drew's comment about blacklist was very helpfull and gulp folks suggest using requirejs directly. So I post my direct requirejs solution:
var DIST = './dist';
var requirejs = require('requirejs');
var requirejsConfig = require('./requireConfig.js').RJSConfig;
gulp.task('requirejs', function (taskReady) {
requirejsConfig.name = 'index';
requirejsConfig.out = DIST + 'app.js';
requirejsConfig.optimize = 'uglify';
requirejs.optimize(requirejsConfig, function () {
taskReady();
}, function (error) {
console.error('requirejs task failed', JSON.stringify(error))
process.exit(1);
});
});
The file at ./dist/app.js is built and uglified. And this way gulp will know when require has finished building. So the task can be used as a dependency.
My solution works like this:
./client/js/main.js:
require.config({
paths: {
jquery: "../vendor/jquery/dist/jquery",
...
},
shim: {
...
}
});
define(["jquery"], function($) {
console.log($);
});
./gulpfile.js:
var gulp = require('gulp'),
....
amdOptimize = require("amd-optimize"),
concat = require('gulp-concat'),
...
gulp.task('scripts', function(cb) {
var js = gulp.src(path.scripts + '.js')
.pipe(cached('scripts'))
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(remember('scripts'))
.pipe(amdOptimize("main",
{
name: "main",
configFile: "./client/js/main.js",
baseUrl: './client/js'
}
))
.pipe(concat('main.js'));
.pipe(gulp.dest(path.destScripts));
}
...
This part was important:
configFile: "./client/js/main.js",
baseUrl: './client/js'
This allowed me to keep my configuration in one place. Otherwise I was having to duplicate my paths and shims into gulpfile.js.
This works for me. I seems that one ought to add in uglification etc via gulp if desired. .pipe(uglify()) ...
Currently I have to duplicate the config in main.js to run asynchronously.
....
var amdOptimize = require("amd-optimize");
...
var js = gulp.src(path.scripts + '.js')
.pipe(cached('scripts'))
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(remember('scripts'))
.pipe(amdOptimize("main",
{
name: "main",
paths: {
jquery: "client/vendor/jquery/dist/jquery",
jqueryColor: "client/vendor/jquery-color/jquery.color",
bootstrap: "client/vendor/bootstrap/dist/js/bootstrap",
underscore: "client/vendor/underscore-amd/underscore"
},
shim: {
jqueryColor : {
deps: ["jquery"]
},
bootstrap: {
deps: ["jquery"]
},
app: {
deps: ["bootstrap", "jqueryColor", "jquery"]
}
}
}
))
.pipe(concat('main.js'));
Try this code in your gulpfile:
// Node modules
var
fs = require('fs'),
vm = require('vm'),
merge = require('deeply');
// Gulp and plugins
var
gulp = require('gulp'),
gulprjs= require('gulp-requirejs-bundler');
// Config
var
requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('app/config.js') + '; require;'),
requireJsOptimizerConfig = merge(requireJsRuntimeConfig, {
name: 'main',
baseUrl: './app',
out: 'result.js',
paths: {
requireLib: 'bower_modules/requirejs/require'
},
insertRequire: ['main'],
// aliases from config.js - libs will be included to result.js
include: [
'requireLib',
"almond",
"underscore",
"jquery",
"backbone",
"text",
"book"
]
});
gulp.task('requirejsBuild', ['component-scripts', 'external-scripts'], function (cb) {
return gulprjs(requireJsOptimizerConfig)
.pipe(gulp.dest('app/dist'));
});
Sorry for my english. This solution works for me. (I used gulp-requirejs at my job)
I think you've forgotten to set mainConfigFile in your gulpfile.js. So, this code will be work
gulp.task('requirejsBuild', function() {
rjs({
name: 'main',
mainConfigFile: 'path_to_config/config.js',
baseUrl: './app',
out: 'result.js'
})
.pipe(gulp.dest('app/dist'));
});
In addition, I think when you run that task in gulp, require can not find its config file and
This is not gulp-requirejs fault.
The reason why only main.js and config.js is in the output is because you're not requiring/defining any other files. Without doing so, the require optimizer wont understand which files to add, the paths in your config-file isn't a way to require them!
For example you could load a main.js file from your config file and in main define all your files (not optimal but just a an example).
In the bottom of your config-file:
// Load the main app module to start the app
requirejs(["main"]);
The main.js-file: (just adding jquery to show the technique.
define(["jquery"], function($) {});
I might also recommend gulp-requirejs-optimize instead, mainly because it adds the minification/obfuscation functions gulp-requirejs lacks: https://github.com/jlouns/gulp-requirejs-optimize
How to implement it:
var requirejsOptimize = require('gulp-requirejs-optimize');
gulp.task('requirejsoptimize', function () {
return gulp.src('src/js/require.config.js')
.pipe(requirejsOptimize(function(file) {
return {
baseUrl: "src/js",
mainConfigFile: 'src/js/require.config.js',
paths: {
requireLib: "vendor/require/require"
},
include: "requireLib",
name: "require.config",
out: "dist/js/bundle2.js"
};
})).pipe(gulp.dest(''));
});

Resources