I don't understand how to work Bower properly - node.js

I'm building a site and I've decided to use a bootstrap template for the back-end (admin tools and whatnot).
I like the look of sb-admin-2 (http://startbootstrap.com/template-overviews/sb-admin-2/) but I'ma bit confused how to practically employ this in my site.
I installed Bower and installed sb-admin using bower install startbootstrap-sb-admin-2
Now I have a folder called bower_components, and it's filled with all the relevant packages... However, these packages include the development files as well.
If I upload this to my site as is, 80% of it will be unnecessary source data.
I'm currently using Gulp with my project, but I don't yet see how the 2 are supposed to interact. Is there a gulp package for compiling the bower_components into 1 concise thing?
I'm new to this kind of workflow and I can't find the answers to the questions despite my efforts. Apologies if I sound like a total noob.

There's no pre-built gulp package that will pull in all your bower source files. You should write a task that pulls in just the files you need. Here's an example from a project I'm working on (simplified):
var scripts = [
'bower_components/timezone-js/src/date.js', // https://github.com/mde/timezone-js
'bower_components/jquery/jquery.min.js', // http://api.jquery.com/
'bower_components/jquery-migrate/jquery-migrate.js', // https://github.com/appleboy/jquery-migrate
'bower_components/jquery-ui/ui/minified/jquery-ui.min.js', // todo: include just the bits we need
'bower_components/jqueryui-touch-punch/jquery.ui.touch-punch.min.js', // https://github.com/furf/jquery-ui-touch-punch
'bower_components/jquery-cookie/jquery.cookie.js', // https://github.com/carhartl/jquery-cookie
'bower_components/jquery.expander/jquery.expander.min.js', // https://github.com/kswedberg/jquery-expander
'bower_components/jquery.transit/jquery.transit.js', // http://ricostacruz.com/jquery.transit/
'bower_components/select2/select2.min.js', // http://ivaynberg.github.io/select2/
'bower_components/fancybox/source/jquery.fancybox.pack.js', // http://fancyapps.com/fancybox/
'bower_components/lodash/dist/lodash.compat.min.js', // https://lodash.com/docs
'bower_components/underscore.string/dist/underscore.string.min.js', // https://github.com/epeli/underscore.string#string-functions
'bower_components/json2/json2.js', // https://github.com/douglascrockford/JSON-js
'bower_components/jquery-validation/dist/jquery.validate.min.js', // http://jqueryvalidation.org/documentation/
'bower_components/jquery-file-upload/js/jquery.iframe-transport.js',
'bower_components/jquery-file-upload/js/jquery.fileupload.js', // https://blueimp.github.io/jQuery-File-Upload/
'bower_components/DataTables/media/js/jquery.dataTables.js', // https://datatables.net/
];
gulp.task('scripts', function () {
return gulp.src(scripts, {base: '.'})
.pipe(plumber())
.pipe(sourcemaps.init({
loadMaps: false,
debug: debug,
}))
.pipe(concat('all_the_things.js', {
newLine:'\n;' // the newline is needed in case the file ends with a line comment, the semi-colon is needed if the last statement wasn't terminated
}))
.pipe(uglify({
output: { // http://lisperator.net/uglifyjs/codegen
beautify: debug,
comments: debug ? true : /^!|\b(copyright|license)\b|#(preserve|license|cc_on)\b/i,
},
compress: { // http://lisperator.net/uglifyjs/compress, http://davidwalsh.name/compress-uglify
sequences: !debug,
booleans: !debug,
conditionals: !debug,
hoist_funs: false,
hoist_vars: debug,
warnings: debug,
},
mangle: !debug,
outSourceMap: true,
basePath: 'www',
sourceRoot: '/'
}))
.pipe(sourcemaps.write('.', {
includeContent: true,
sourceRoot: '/',
}))
.pipe(plumber.stop())
.pipe(gulp.dest('www/js'))
});
I'm cherry-picking the source files I want, combining and minifying them, and dumping them into my public directory so that can be served to the client. You don't need to upload the bower_components folder to your production server; but it probably wouldn't hurt much either (it's not THAT big!).

Related

How to setup gulp-watch with gulp-connect livereload?

Most questions and answers on this site do not contain an easy-to follow general approach to using these two libraries together.
So, being that we use the gulp-connect npm package, and we want to make use of the gulp-watch npm package, how do we set it up so that we can:
watch changes in some files
perform some operation, like building / compiling those files
live-reload the server once the building is done
First, you will define your build task. This can have pre-required tasks, can be a task of some sort, it doesn't matter.
gulp.task('build', ['your', 'tasks', 'here']);
Then, you will need to activate the connect server. It is important that you are serving the result of the compilation (in this example, the dist directory) and you're enabling livereload with the livereload: true parameter.
const connect = require('gulp-connect');
gulp.task('server', function() {
return connect.server({
root: 'dist',
livereload: true
});
});
Finally, you will setup your watch logic. Note that we're using watch and not gulp.watch. If you decide to change it, notice that their APIs are different and they have different capabilities. This example uses gulp-watch.
const watch = require('gulp-watch');
gulp.task('watch-and-reload', ['build'], function() {
watch(['src/**'], function() {
gulp.start('build');
}).pipe(connect.reload());
});
gulp.task('watch', ['build', 'watch-and-reload', 'server']);
The watch-and-reload task will depend on the build task, so that it ensures to run at least one build.
Then, it will watch for your source files, and in the callback, it will start the build task. This callback gets executed every time that a file is changed in the directory. You could pass an options object to the watch method to be more specific. Check the usage API in their repository.
Also, you will need to start the build action, for which we're using gulp.start. This is not the recommended approach, and will be deprecated eventually, but so far it works. Most questions with these issues in StackOverflow will look for an alternative workaround that changes the approach. (See related questions.)
Notice that gulp.start is called synchronously. This is what you want, since you want to allow the build task to finish before you proceed with the event stream.
And finally, you can use the event stream to reload the page. The event stream will correctly capture what files changed and will reload those.
Bringing up to speed, as per current stable gulp release
gulp.task API isn't the recommended pattern anymore. Use exports object to make public tasks
From official documentation: https://gulpjs.com/docs/en/api/task#task
To Configure watch and livereload you need following
gulp.watch
gulp-connect
watch function is available in gulp module itself
install gulp-connect using npm install --save-dev gulp-connect
To configure gulp-connect server for livereload we need to set property livereload to true
Run all tasks followed by task that calls watch function in which globs and task are given. Any changes to files that match globs trigger task passed to watch().
task passed to watch() should signal async complection else task will not be run a second time. Simple works: should call callback or return stream or promise
Once watch() is configured, append .pipe(connect.reload()) followed by pipe(dest(..)) where ever you think created files by dest are required to reload
Here is simple working gulpfile.js with connect lifereload
const {src, dest, watch, series, parallel } = require("gulp");
const htmlmin = require("gulp-htmlmin");
const gulpif = require("gulp-if");
const rename = require('gulp-rename');
const connect = require("gulp-connect");
//environment variable NODE_ENV --> set NODE_ENV=production for prouduction to minify html and perform anything related to prod
mode = process.env.NODE_ENV || 'dev';
var outDir = (mode != 'dev') ? 'dist/prod': 'dist/';
const htmlSources = ['src/*.html'];
function html() {
return src(htmlSources)
.pipe(gulpif(
mode.toLowerCase() != 'dev',
htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})
)
)
.pipe(dest(outDir))
.pipe(connect.reload());
}
function js(){
return src('src/*.js')
.pipe(uglify())
.pipe(rename({ extname: '.min.js' }))
.pipe(dest(outDir))
.pipe(connect.reload());
}
function server() {
return connect.server({
port: 8000,
root: outDir,
livereload: true
})
}
function watchReload() {
let tasks = series(html, js);
watch(["src/**"], tasks);
}
exports.html = html;
exports.js = js;
exports.dev = parallel(html, js, server, watchReload);
Configure connect server with livereload property
function server() {
return connect.server({
port: 8000,
root: outDir,
livereload: true //essential for live reload
})
}
Notice .pipe(connect.reload()) in the above code. It is essential that stream of required files to be piped to connect.reload() else it may not work if you call connect.reload() arbitrarily
function html() {
return src(htmlSources)
.pipe(gulpif(
mode.toLowerCase() != 'dev',
htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})
)
)
.pipe(dest(outDir))
.pipe(connect.reload()); //Keep it if you want livereload else discard
}
Since we configure public task dev following command will execute all tasks followed by connect and watchReload
gulp dev

How to tell systemjs to ignore an import

This is for the systemjs library, not systemjs-builder
I might have a bit of an edge case here. But I'm trying to setup my frontend web application to run it's unit tests in the command line. My setup currently builds the typescript to the systemjs register format and loads is imported into the site as per their specifications. The issue I am currently facing is that one of my dependencies reflect-metadata has a node auto detect system that makes a require('crypto') call, which is a native node module (not available in npm). The error I am receiving is:
Error: ENOENT: no such file or directory, open '/Users/path/to/project/node_modules/crypto.js'
There are lots of things at play here I understand, but the behavior I am after is for systemjs to completely ignore the require('crypto') call and allow it to pass through completely unchanged as node will correctly load this at runtime.
Due to the multi-module enterprise application we are creating I don't really have the freedom to export the typescript to commonjs due to sub-dependencies receiving the Systemjs version rather then a temp commonjs build. (The only way to do this would be to include the commonjs version in our private npm dist build, which is far from ideal)
Here is the current config I am using for system as I have been attempting to get system to ignore the crypto library require. I've left this in the exact state it was when the above error was generated, comments and all so you could see what I've tried.
System.config({
defaultJSExtensions: true,
map: {
'angular2': 'node_modules/angular2',
'reflect-metadata': 'node_modules/reflect-metadata/Reflect',
'crypto': 'node_modules/crypto'
}
// packages: {
// 'reflect-metadata': {
// format: 'global',
// exports: 'Reflect',
// defaultExtension: false,
// meta: {
// '*': {
// defaultExtension: false
// }
// }
// }
// }
// meta:{
// 'reflect-metadata/Reflect':{
// format: 'global',
// exports: 'Reflect',
// defaultExtension: false
// }
// }
});
To ignore a require you can map it to the #empty module within your SystemJS config file.
you can do this by by adding System.config({ map: { 'crypto': '#empty' } })

Grunt CSS min - Issue with minifying different CSS files

I'm having issue with minifying multiple CSS files using grunt cssmin I'm not looking to minify all files into single file. I would like to have the files having same name with min.css extension.
My gruntfile.js is as follows.
module.exports = function (grunt) {
grunt.initConfig({
cssmin: {
target: {
files: [{
src: ['assets/css/*.css', '!assets/css/*.min.css'], // source files mask
dest: 'assets/css/', // destination folder
expand: true, // allow dynamic building
flatten: true, // remove all unnecessary nesting
ext: '.min.css' // replace .css to .min.css
}],
/* BELOW IS ONLY A TRICK USED TO MINIFY THE FILES SKIPPED BY THE ABOVE */
/*files: [{
src: ['assets/css/home.css', 'assets/css/institutions.css', 'assets/css/form-elements.css'], // source files mask
dest: 'assets/css/', // destination folder
expand: true, // allow dynamic building
flatten: true, // remove all unnecessary nesting
ext: '.min.css' // replace .css to .min.css
}],*/
}
}
});
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('default', [ 'cssmin' ]);
};
As per the code (except the commented out part), it is suppose to minify all the css files. But for some reason it skips few css files from the directory. To minify those, I have to comment out the first files[{}] and uncomment the later.
It doesn't work when both files[{}] are uncommented. I'm clueless on why its happening.
My Nodejs version is: v0.10.25
Thanks in advance.
Note: I used to get warnings & task aborts on grunt cssmin due to node version issue and got it fixed by downgrading nvm version to nvm v0.10.39. Thanks to blindMoe for pointing the solution

Durandal optimization with Gulp and Gulp-Durandal not working

We are building an application with Durandal which is quite big at the moment and we currently looking into bundling all JS files located in the App folder into a main-built.js file. Pretty basic and usual stuff I guess.
I'm using Gulp with the Gulp-Durandal extension. Here our gulpfile :
var gulp = require('gulp');
var durandal = require('gulp-durandal');
gulp.task('build-portal', function () {
durandal({
baseDir: 'app',
main: 'main.js',
output: 'main-built.js',
almond: false,
minify: false
}).pipe(gulp.dest('app'));
});
And here's a snippet of our main.js file
require.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions'
},
shim: {
},
waitSeconds: 0
});
define('jquery', [], function () { return jQuery; });
define('knockout', [], function () { return ko; });
define('ga', function () { return ga; });
define(
["require", "exports", "durandal/app", "durandal/viewLocator", "durandal/system", "plugins/router", "services/logger", "modules/knockout.extensions", "modules/knockout.validation.custom"],
function (require, exports, __app__, __viewLocator__, __system__, __router__, __logger__, __koExtensions__, __koValidationCustom__) {
var app = __app__;
var viewLocator = __viewLocator__;
var system = __system__;
var router = __router__;
As you can see in the gulpfile, we do not want to use Almond but RequireJs instead, for some reasons almond isn't workin with our project and anyhow, we prefer RequireJs whether its bigger than almond at the end. That's where it look to brake. Running the command to build the main-built.js file took sometime but at the end I get the file built with everything in it.
The problem is that when I try to load the application, it is stuck to the loading screen. It doesn't go any further and there's no errors at all in the browser console.
I created a new project on the side to test if our code was somewhat faulty and found that it might not. You can found that project here :
https://github.com/maroy1986/DurandalGulpBundling
If I build that project with almond option to true, everything works fine but if I switch almound off to tell gulp to use RequireJs, I got the same behavior as our app. You got stuck at the loading screen, without any errors.
So here I am, I do read a lot on the subject but didn't found anything to solve this. Hope someone here already encounter these behavior and have a solution to share.
Thanks!
I had the same requirement and issue. It seems require.js wasn't calling the main module which will startup the Durandal app, that's why it's stuck in the loading screen. I was able to resolve it by implicitly calling the main module:
gulp.task("durandal", function() {
return durandal({
baseDir: "app",
main: "main.js",
output: "main-built.js",
almond: false,
minify: true,
rjsConfigAdapter: function(config) {
//Tell requirejs to load the "main" module
config.insertRequire = ["main"];
return config;
}
})
.pipe(gulp.dest("dist"));
});
I downloaded your project and tried building it with the latest versions of gulp and durandal. Initially it didn't build and gave me the following error:
TypeError: Cannot read property 'normalize' of undefined
This is a problem with the text-plugin of rjs and you can solve this by adding the following to your gulp-file (next to the almond, minify, output... properties):
rjsConfigAdapter : function(rjsConfig){
rjsConfig.deps = ['text'];
return rjsConfig;
}
Once I did that, the build finished and I could build with or without minify, almond and require and the application works fine.

Using AWS credentials in a public GitHub repo (in a node.js project, built with Grunt.js)

We have a MEAN (nodes.js back-end + angular front-end), where we use the Amazon S3 sdk to upload files to the storage service. We have our AWS credentials and we need to use them in the code.
We would like to publish our project in a public repository, but we don't want to share our credentials (by the way, Amazon monitors GitHub and notifies developers who disclose their credentials). How should we adapt our development workflow to have something secure (no disclosure) and convenient?
The solution consists in tuning the Gruntfile.js file, which defines what needs to be done during the build process. Depending on the one that you use as a starting point, things will be a bit different (and various use cases might need to be considered).
In our case, we use the angular fullstack yeoman generator (https://github.com/DaftMonk/generator-angular-fullstack) to generate the project skeleton. The Gruntfile.js that is produced by the generator is fairly sophisticated, so we had to edit a couple of sections. Here are the key points:
1. Passing arguments to Grunt
The first thing that we need, is to be able to invoke the build process and to pass arguments. The arguments should not end up in the repository, so developers should create a script outside the codebase to launch the build process (or type the arguments manually each time...). Grunt gives the ability to access command line arguments with the grunt.option() function. So, the first modification to the Gruntfile.js file is to add the following two lines right at the beginning:
module.exports = function (grunt) {
var amznUserId = grunt.option('AMZN_USER_ID');
var amznUserPassword = grunt.option('AMZN_USER_PASSWORD');
...
}
If you do that and then invoke grunt by typing:
grunt build --AMZN_USER_ID=myUserId --AMZN_USER_PASSWORD=aSecret
grunt serve --AMZN_USER_ID=myUserId --AMZN_USER_PASSWORD=aSecret
Then you will have the credential values available in the script variables.
2. Adding placeholders in the source files
The AMZN credentials are used in an Angular.JS component, typically in a controller. What you need to do is to replace the hard-coded values with variable placeholders, like this:
angular.module('demoApp')
.controller('MainCtrl', function ($scope, $http, socket) {
$scope.amzn_user_id = '##AMZN_USER_ID';
$scope.amzn_user_password = '##AMZN_USER_PASSWORD';
3. Injecting command line arguments into the placeholders
The last (and most tricky) part of the solution consists of injecting the 2 values passed to grunt into the placeholders. There are different Grunt plugins that can be used for this purpose. We have used the grunt-replace plugin with success. Here is what we had to do:
3.1 Install the plugin
npm install grunt-replace --save
3.2 Configure the plugin (specify how the injection should happen, more on this at the end)
grunt.initConfig({
replace: {
dist: {
options: {
patterns: [
{
match: 'AMZN_USER_ID',
replacement: amznUserId
},
{
match: 'AMZN_USER_PASSWORD',
replacement: amznUserPassword
}
]
},
files: [
{
expand: true,
flatten: false,
src: ['.tmp/concat/app/app.js'],
dest: '.'
},
{
expand: false,
flatten: false,
src: ['client/app/main/main.controller.js'],
dest: '.tmp/app/main/main.controller.js'
}
]
}
},
3.3. Invoke the plugin in the grunt build and grunt serve workflows
Please note that the order is important and that the replace lines must be exactly in that position.
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'env:all', 'env:prod', 'express:prod', 'wait', 'open', 'express-keepalive']);
}
if (target === 'debug') {
return grunt.task.run([
'clean:server',
'env:all',
'injector:stylus',
'concurrent:server',
'injector',
'wiredep',
'autoprefixer',
'concurrent:debug'
]);
}
grunt.task.run([
'clean:server',
'env:all',
'injector:stylus',
'concurrent:server',
'injector',
'wiredep',
'replace',
'autoprefixer',
'express:dev',
'wait',
'open',
'watch'
]);
});
and
grunt.registerTask('build', [
'clean:dist',
'injector:stylus',
'concurrent:dist',
'injector',
'wiredep',
'useminPrepare',
'autoprefixer',
'ngtemplates',
'concat',
'replace',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'rev',
'usemin'
]);
What happens behind the scenes
The key point is to realize that the angular fullstack generator defines a build workflow, where a special directory named .tmp is used. The content of this directory is not always the same (grunt build and grunt serve use it in slightly different ways). That is the reason why we had to define two replacement rules.

Resources