I have an AngularJS application and in the future, some developers in other teams will develop modules that will be installed as parts of it. So I defined the folder structure as below.
www/
index.html
app.js
modules/
modulesA/ -- will be copied when module A was installed
moduleA.js
moduleA.css
moduleA.partial.html
modulesB/ -- will be copied when module B was installed
moduleB.js
moduleB.css
moduleB.partial.html
Now I have a problem. When user installed module A, how to let AngularJS (and the application) load JS and CSS under its folder? Is there any library can load JS and CSS by folder so that I can put the code in index.html likes
<script src="/modules/**/*.js"></script>
<link src="/modules/**/*.css"/>
Otherwise, I have to add some placesholders in index.html and change the content when user installed a module, something like
<script src="/app.js"></script>
<!-- $$_JS_$$ -->
<link src="/app.css"/>
<!-- $$_CSS_$$ -->
AngularJS doesn't support what you want, but you could take a look at build tools such as Grunt or Gulp that let you "build" your application for you. In your case, these tools can look for CSS files and concatenate them into one single file. This way your index.html does not have to change if you ever add new modules.
GruntJS: http://gruntjs.com/
GulpJS: http://gulpjs.com/
Personally I use GulpJS, since it seems to be much faster & I found it easier to configure:
Included my configuration file below.
For example, the task "styles" will compile every css file it finds in the folders I specified, concatenate them, and drop them in the distribution folder.
Since there is an initial learning curve on how to use these tools, you can always integrate gulp or grunt at your own pace. For now you could let it build your css files & later expand it by concatenating JS as well and do various other tasks. In my opinion, its worth learning as it saves you so much time & effort.
var gulp = require("gulp");
var concat = require("gulp-concat");
var html2js = require("gulp-ng-html2js");
var sass = require("gulp-sass");
var clean = require("gulp-clean");
var streamqueue = require("streamqueue");
var ngDepOrder = require("gulp-ng-deporder");
var paths = {
"dist": "../server/staffing/static/",
"vendor": ['vendor/underscore/underscore.js',
'vendor/angular/angular.min.js',
'vendor/angular-route/angular-route.min.js',
'vendor/restangular/dist/restangular.min.js',
'vendor/angular-animate/angular-animate.min.js',
'vendor/angular-bootstrap/ui-bootstrap-0.7.0.min.js',
'vendor/angular-bootstrap/ui-bootstrap-tpls-0.7.0.min.js',
'vendor/angular-ui-router/release/angular-ui-router.min.js',
'vendor/angular-bootstrap-colorpicker/js/bootstrap-colorpicker-module.js',
'vendor/momentjs/min/moment.min.js'],
"scripts": ['app/**/*.js'],
"fonts": ['app-data/fonts/*.*'],
"templates": ['app/**/*.html'],
"styles": ['app/**/*.scss','vendor/angular-bootstrap-colorpicker/css/*.css']
}
gulp.task("watch", function () {
gulp.watch('app/**/*.js', ['scripts']);
gulp.watch('app/**/*.html', ['scripts'])
gulp.watch('app/**/*.scss', ['styles']);
})
gulp.task("default", ["clean"], function () {
gulp.start("scripts", "vendor", "styles", "fonts");
})
gulp.task("clean", function () {
return gulp.src(paths.dist, {read: false})
.pipe(clean({force: true}));
})
gulp.task("vendor", function () {
gulp.src(paths.vendor)
.pipe(concat("vendor.js"))
.pipe(gulp.dest(paths.dist + "js/"));
});
gulp.task("scripts", function () {
var stream = streamqueue({objectMode: true});
stream.queue(gulp.src(paths.scripts)
.pipe(ngDepOrder()));
stream.queue(gulp.src(paths.templates)
.pipe(html2js({moduleName: "templates"})));
return stream.done()
.pipe(concat("app.js"))
.pipe(gulp.dest(paths.dist + "js/"))
});
gulp.task("styles", function () {
gulp.src(paths.styles)
.pipe(sass())
.pipe(concat("staffing.css"))
.pipe(gulp.dest(paths.dist + "css/"))
})
gulp.task("fonts", function () {
gulp.src(paths.fonts).
pipe(gulp.dest(paths.dist + "fonts/"))
})
Check out the angular generator for Slush, it does what I think you want using gulp-bower-files and gulp-inject. You specify your app dependencies using bower, and these are collected and injected by gulp using gulp-inject, which then injects in your index.html the proper link/src/style tags that look very much like your own examples above. Modules' JS and CSS is also collected, minimized, concatenated and injected as well. It also compiles partials and injects those into $templateCache.
I have used it to automatically include dependencies from sub-folder modules/views using a project layout similar to yours.
Note that all your vendor dependencies will need to be bower packages that specify their dist files using the 'main' attribute in bower.json. Some packages do not do this properly, but it's easy to fork the package and add them yourself then point bower at your updated repo.
Related
Thanks for reading. I am new to gulp, so apologizing if its a dumb question. I have an AngularJS project with the following folder structure:
app/
app.js
modules/
mod1/
index.js
mod1.js
another.js
mod2/
... same structure as mod1
To create a bundle using browserify I am using this:
gulp.task('bundle', function() {
return browserify('app/app.js')
.bundle()
.pipe(vinylSource('bundle.js'))
.pipe(gulp.dest('public/js'));
});
To make this work, I have include require('mod1') ..require('another') and so on.
I always have to make sure that I am requiring the script that I need to use.
My goal is to create a bundle that includes all javascript file inside my app folder starting from app.js without getting into dependency conflicts and without me writing require('somefile').
You can get that by just using the gulp-concat plugin.
You just specify the paths to search. Because you're using angular and need the modules defined before everything else, I'd add the app first, then all the module definitions, then remaining directives and controllers etc after.
var gulp = require('gulp');
var concat = require('gulp-concat');
gulp.task('app-js', function() {
return gulp.src([
'./app/app.js',
'./app/**/mod*.js',
'./app/**/*.js',
])
.pipe(concat('bundle.js'))
.pipe(gulp.dest('public/js'))
});
I've got a gulpfile.js that bundles using browserify and I want to be able to optionally add one line to one of my javascript files based on a variable like useMock. Below is my GulpFile.js build step
function bundle (bundler) {
return bundler
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./dist'))
.pipe(browserSync.stream());
}
The last line of the file below is the one I want to optionally include.
module.exports = require('angular')
.module('AngularUApp', [
require('angular-ui-router'),
require('angular-sanitize'),
require('../../base'),
require('./home'),
require('./speaker'),
require('./author')
])
.config(enableHtml5Mode)
.name;
enableHtml5Mode.$inject = ['$locationProvider'];
function enableHtml5Mode($locationProvider) {
console.log('enableHtml5Mode');
$locationProvider.html5Mode(true);
}
// I want to optionally include this from my gulpfile.js
require('../mock');
I want to be able to have a production and dev build where the dev includes the extra line and production does not. If there is a better more recommended way to do this, please suggest.
I found the answer myself. Using the browserify api itself from this link:
https://github.com/substack/node-browserify#usage
var combinedArgs = merge(watchify.args, { debug: true });
var b = browserify(baseDir,combinedArgs);
b.add('angu/mock');
var watcher = watchify(b);
I had a problem earlier because I forgot the relative directory from gulp is different than from inside the JavaScript itself.
I'm using VS 2015, ASP.NET 5 (MVC 6) and Gulp to write a SPA with angularjs and supplementary modules. My target framework is dnx451. I've read several best practices which state that the response from Index should have a strict no cache policy set, and all other resources (e.g. js, css, img) should all be heavily cached. In doing so, the browser always downloads the lightweight page and caches the scripts. When publishing, I am trying to have a gulp task which concats/uglifys all my JS files and outputs a single app.min.{version}.js (also for the less -> css file). This gives the benefit of always downloading the latest file version, but keeping them in cache while it is the latest and greatest.
Is there a way to get the Version (from project.json) and the build (from the * portion of project.json) from my gulp task? I am looking for a way to have the file {version} portion of the name match the version/build of the website.
I have seen examples of using process.env in gulp for VS environment variables, but am having trouble putting the pieces together to achieve the desired Version.Build format.
I have tried:
var project = require('./project.json');
gulp.task('js-publish', function(){
project.version; //this give 1.0.0-* (makes sense since its a string)
});
and
gulp.task('js-publish', function(){
process.env.BUILD_VERSION; //which is undefined
});
You want to use the gulp-rename NPM package to rename the file. Add gulp-rename to your package.json file. Here is an example of how it can then be used in your gulpfile.js:
var rename = require("gulp-rename");
// rename via string
gulp.src("./src/main/text/hello.txt")
.pipe(rename("main/text/ciao/goodbye.md"))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/goodbye.md
// rename via function
gulp.src("./src/**/hello.txt")
.pipe(rename(function (path) {
path.dirname += "/ciao";
path.basename += "-goodbye";
path.extname = ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/hello-goodbye.md
// rename via hash
gulp.src("./src/main/text/hello.txt", { base: process.cwd() })
.pipe(rename({
dirname: "main/text/ciao",
basename: "aloha",
prefix: "bonjour-",
suffix: "-hola",
extname: ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/bonjour-aloha-hola.md
I'm part of a team developing an AngularJS application and right now I'm working on modifying the Gulp build script. Part of my task is prepopulating the template cache (up till now we have been loading the templates as the routes/directives needed them).
The Gulp task is basically:
var templateCache = require('gulp-angular-templatecache');
gulp.task('cache-templates', function(){
var dest = destinationPath,
src = sourcePath;
return gulp.src(src)
.pipe(plumber())
.pipe(templateCache('templates.js', {root: './templates/'}))
.pipe(gulp.dest(dest));
});
The problem I am getting is that gulp removes the "./" from the root. For instance:
$templateCache.put("templates/foo.html","<div>some html</div>");
in stead of
$templateCache.put("./templates/foo.html","<div>some html</div>");
The module is loaded correctly into app.js and declared as a dependency, and if I do put the "./"'s as a prefix manually, after building, everything works fine. So could you please tell me how to force Gulp to include the "./" prefix in my root?
Note: Every other prefix works fine, it just removes the "./". I would prefer it if I could solve this from within the Gulpfile, without having to modify the templateUrl's in my directives and $routeProvider, because the application is rather large and that would only be asking for trouble. Thanks! :)
What you can do is use gulp-replace and replace 'templates/' with './templates/'.
Old Answer
In the options that you pass to template you can provide a base function
.pipe(templateCache('templates.js', {root: './templates/', base: baseFn}))
you can modify the file-path there
var baseFn = function (file) { return './' + file.relative; }
i'm trying to get all the files in my bower components using main bower files and filtering them according type using gulp-filter. it works fine when i filter out the js files like so:
gulp.task('bower_js', function() {
var jsFilter = gulpFilter('**/*.js');
gulp.src(mainBowerFiles(), {base: './bower_components'})
.pipe(jsFilter)
.pipe(concat('vendor.js'))
.pipe(gulp.dest('./_public/js'));
});
however running a similar task for less doesn't work (ie nothing goes through the filter):
gulp.task('bower_css', function() {
var lessFilter = gulpFilter('**/*.less');
gulp.src(mainBowerFiles(), {base: './bower_components'})
.pipe(lessFilter)
// .pipe(less()) commented to narrow down the problem
.pipe(concat('app.css'))
.pipe(gulp.dest('./_public/css'));
});
although if I run mainBowerFiles without any filter.. it dumps .less files content into my destination folder..
to give a specific example.. this is the relevant part of bower.json of one of my bower packages: bootstrap:
"main": [
"less/bootstrap.less",
"dist/css/bootstrap.css",
"dist/js/bootstrap.js",
"dist/fonts/glyphicons-halflings-regular.eot",
"dist/fonts/glyphicons-halflings-regular.svg",
"dist/fonts/glyphicons-halflings-regular.ttf",
"dist/fonts/glyphicons-halflings-regular.woff"
],
bootstrap.less in turn imports other files:
// Core variables and mixins
#import "variables.less";
#import "mixins.less";
// Reset and dependencies
#import "normalize.less";
#import "print.less";
..
and so on.
any ideas?
I've been trying to get something similar to work for SASS with no luck. That is until I found that main-bower-files now has a filter option built in. It's a regular expression. Try something like this instead of using gulp-filter:
gulp.task('bower_css', function() {
var lessRegEx = (/.*\.less$/i);
gulp.src(mainBowerFiles({filter: lessRegEx}), {base: './bower_components'})
// .pipe(less()) commented to narrow down the problem
.pipe(concat('app.css'))
.pipe(gulp.dest('./_public/css'));
});
Experiencing same issue with fonts folder, strange combo for main-bower-files (2.11.0) and gulp-filter (v3.0.1).
Issue #53 in gulp-filter looks similar, the solution seams to be the basedir option.
main-bower-files + gulp-filter = not working
gulp.src(mainBowerFiles())
.pipe(gulpFilter('**/fonts/*'))
.pipe(gulp.dest('./demo/assets/fonts'));
main-bower-files + basedir + gulp-filter = working
gulp.src(mainBowerFiles(), {base: './'})
.pipe(gulpFilter('**/fonts/*'))
.pipe(gulp.dest('./demo/assets/fonts'));
main-bower-files with filter = working
gulp.src(mainBowerFiles('**/fonts/*'))
.pipe(gulp.dest('./demo/assets/fonts'));
simple gulp.src + gulp-filter = working
gulp.src('bower_components/**')
.pipe(gulpFilter('**/fonts/*'))
.pipe(gulp.dest('./demo/assets/fonts'));