Following angular 2 quick start guide, guys there use typescript compiler and tsconfig.json file, to work with it. I was looking up ways to use gulp for this and indeed there seem to be ways to achieve this, however I'm a bit confused to correct implementation with angular 2.
essentially gulp-typescript and gulp-tslint seem to be two plugins to achieve this and somehow tsconfig.json file is also in play here, although I don't grasp why.
Could anyone provide example for implementation that will achieve above? I believe all development .ts files should be within src folder and javascript needs to be pumped over to build folder. (assume for now that both folders have setup from angular 2 quick start)
I've setup gulp to work from gulpfile.js/ folder. In this folder are index.js, config.js and tasks/ folder, and in tasks/typescript.js is task that compiles TypeScript (tasks folder has 15 other tasks). So instead of one huge gulpfile.js I have manageable chunks that each do just one thing...
gulpfile.js/index.js
var gulp = require('gulp');
var config = require('./config.js');
var plugins = require('gulp-load-plugins')();
plugins.brsync = require('browser-sync').create();
plugins.builder = require('systemjs-builder');
function run(name) {
return require('./tasks/' + name)(gulp, plugins, config);
}
// ...other tasks, in alphabetical order! (:
gulp.task('typescript', run('typescript'));
gulpfile.js/config.js
var distDir = 'dist';
var staticDir = isGAE() ? '/static' : '';
module.exports = {
SRC: {
TYPESCRIPT: 'src/scripts/**/*.ts',
},
DST: {
MAPS: './maps',
SCRIPTS: distDir + staticDir + '/scripts',
},
};
gulpfile.js/tasks/typescript.js
module.exports = function (gulp, plugins, CONFIG) {
return function typescript() {
var tsProject = plugins.typescript.createProject('tsconfig.json');
var tsReporter = plugins.typescript.reporter.fullReporter();
var stream = gulp
.src(CONFIG.SRC.TYPESCRIPT, { since: gulp.lastRun('typescript') })
.pipe(plugins.sourcemaps.init())
.pipe(plugins.typescript(tsProject, undefined, tsReporter))
.pipe(plugins.sourcemaps.write(CONFIG.DST.MAPS,
{sourceMappingURLPrefix: '/scripts'}))
.pipe(gulp.dest(CONFIG.DST.SCRIPTS))
.on('error', plugins.util.log);
return stream;
};
};
gulpfile.js/tasks/watch.js
module.exports = function (gulp, plugins, CONFIG) {
return function watch() {
plugins.brsync.init(CONFIG.BRSYNC);
gulp.watch(CONFIG.SRC.TEST, () => queue_tasks(['karma']));
gulp.watch(CONFIG.SRC.TYPESCRIPT, () => queue_tasks(['typescript'], brsync_reload));
};
};
I had an issue with gulp watch: if you're watching files, work on more then one file and save them all it will run a task multiple times, which can be annoying. Check the link for implementation of queue_tasks() function...
Also note that I'm using Gulp 4:
gulp.src(CONFIG.SRC.TYPESCRIPT, { since: gulp.lastRun('typescript') })
I've added in src() option since to cache files, and pass only changed files down the pipe. I implemented this just 2 days ago and didn't test it with typescript files (works in other places), so if there are issues just remove it...
Related
I'm trying to watch some files in a directory and automatically update there documentation with jsdoc. I use gulp to watch the file and run jsdoc see code below.
const gulp = require('gulp');
const watch = require('gulp-watch');
const jsdoc = require('gulp-jsdoc3');
gulp.task('doc', function(cb) {
const config = require('./jsdoc.json');
return watch(['../upload/**/*.js'], { ignoreInitial: false })
.pipe(jsdoc(config, cb));
});
When I run this task it doesn't update my jsdoc when a file is changed. Does jsdoc not work together with the watch function?
It´s not sure that the problem comes from gulp-jsdoc3. Maybe you want to split your task into two tasks.
task for the job and the
for the watcher
const gulp = require('gulp');
const watch = require('gulp-watch');
const jsdoc = require('gulp-jsdoc3');
gulp.task('jsdoc-task', function() {
console.log('task is running')
const config = require('./jsdoc.json');
return gulp.src( 'scr/files' )
.pipe(jsdoc(config)).
.pipe(gulp.dest( 'your destination path ));
});
gulp.task('watch', function() {
gulp.watch('files-to-watch', [jsdoc-task]);
});
Please note there is no return for the watcher and also the files to watch src should not be the same as the output destination files.
You can now see the consol.log and check out if the task was started.
Now it should be easier to find out whats going wrong. If it´s not working check out the error message for more details.
I'm configuring Grunt with grunt-contrib-concat to concatenate like 20 javascript files. They have to be in a specific order and I'm wondering if there is a neat way to do this, without messing up my Gruntfile.js.
What I did and what worked well, was declaring an variable called 'libraries' with a function which returned a string with all the files in the right order.
var libraries = new (function () {
return [
'/javascript/libs/jquery.min.js',
'/javascript/libs/jquery.address.js',
'/javascript/libs/jquery.console.js'
];
});
And then concat (simplified, just an example):
concat: {
libs: {
files: {
'libs.js' : [libraries],
},
},
main: {
files: {
'main.js' : [main]
}
}
},
So when I call 'libraries' in my task configuration everything works fine, but I would like to declare this list in a separate file.
Unfortunately I couldn't find anything, nor do I know if this is even possible. Hope that someone could help me out! Thanks in advance :-)
I found a solution! Since Grunt is build on NodeJS, it's possible to use module.exports. What I did was setting an external file called libraries.js, which is in my Grunt directory.
var exports = module.exports = {};
exports.customLibrary = function () {
return [
// Path to a library
// Path to another library
// and so on...
];
};
exports.mainScripts = function () {
return [
// Path to a library
// Path to another library
// and so on...
];
};
Then I import this module by declaring a variable in Gruntfile.js
var libraries = require('../javascript/libraries.js');
To use the methods declared in libraries.js I set two more variables which returns a string with all the necessary files in the desired order:
var customLibrary = libraries.customLibrary();
var mainScripts = libraries.mainScripts();
I use these variables to define the source in the concat task. Hope this is helpful!
I need to run some gulp task on two different folder only.
Example of my project folder structure:
- Project
- componentA
- componentB
- componentC
- componentD
I need to perform tasks in componentA and componentB and not in C/D.
At the moment I am using the following script.
Could you please tell me how to add the task for B?
Do you know any alternative/better approach?
// include gulp
var gulp = require('gulp');
// include plug-ins
var jshint = require('gulp-jshint');
// JS hint task
gulp.task('jshint', function () {
gulp.src('./componentA/**/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
The below uses a match to exclude C and D directly
(note I'm using concat for testing)
var gulp = require('gulp');
var concat = require('gulp-concat');
var files = './component!(C|D)/*.txt';
gulp.task('test', function(){
gulp.src(files)
.pipe(concat('all.txt'))
.pipe(gulp.dest('./'));
});
Which for you would be
'./component!(C|D)/**/*.js'
I was able to solve this issue using the following code.
Any better way or alternative approaches are welcome.
// include plug-ins
var jshint = require('gulp-jshint');
var folders = [
'./componentA/**/*.js',
'./componentB/**/*.js'
];
// JS hint task
gulp.task('jshint', function () {
gulp.src(folders)
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
I managed to accomplish my task using a gulp plugin called gulp-insert like this:
gulp.task('compile-js', function () {
// Minify and bundle client scripts.
var scripts = gulp.src([
srcDir + '/routes/**/*.js',
srcDir + '/shared/js/**/*.js'
])
// Sort angular files so the module definition appears
// first in the bundle.
.pipe(gulpAngularFilesort())
// Add angular dependency injection annotations before
// minifying the bundle.
.pipe(gulpNgAnnotate())
// Begin building source maps for easy debugging of the
// bundled code.
.pipe(gulpSourcemaps.init())
.pipe(gulpConcat('bundle.js'))
// Buffer the bundle.js file and replace the appConfig
// placeholder string with a stringified config object.
.pipe(gulpInsert.transform(function (contents) {
return contents.replace("'{{{appConfigObj}}}'", JSON.stringify(config));
}))
.pipe(gulpUglify())
// Finish off sourcemap tracking and write the map to the
// bottom of the bundle file.
.pipe(gulpSourcemaps.write())
.pipe(gulp.dest(buildDir + '/shared/js'));
return scripts.pipe(gulpLivereload());
});
What I'm doing is reading our app's configuration file which is managed by the config module on npm. Getting our config file from server-side code is a snap using var config = require('config');, but we're a single-page app and frequently need access to the configuration settings on the client-side. To do that I stuff the config object into an Angular service.
Here's the Angular service before gulp build.
angular.module('app')
.factory('appConfig', function () {
return '{{{appConfigObj}}}';
});
The placeholder is in a string so that it's valid JavaScript for some of the other gulp plugins that process the file first. The gulpInsert utility lets me insert the config like this.
.pipe(gulpInsert.transform(function (contents) {
return contents.replace("'{{{appConfigObj}}}'", JSON.stringify(config));
}))
This works but feels a little hacky. Not to mention that it has to buffer the whole bundled file just so I can perform the operation. Is there a more elegant way to accomplish the same thing? Preferably one that allows the stream to keep flowing smoothly without buffering the whole bundle at the end? Thanks!
Have you checked gulp-replace-task?
Something like
[...]
.pipe(gulpSourcemaps.init())
.pipe(replace({
patterns: [{
match: '{{{appConfigObj}}}',
replacement: config
}],
usePrefix: false
})
.pipe(gulpUglify())
[...]
Admittedly, this feels a bit hacky, too, but maybe slightly better... I'm using envify and gulp-env in a React project. You could do something like this.
gulpfile.js:
var config = require('config');
var envify = require('envify');
gulp.task('env', function () {
env({
vars: {
APP_CONFIG: JSON.stringify(config)
}
});
});
gulp.task('compile-js', ['env'], function () {
// ... replace `gulp-insert` with `envify`
});
factory:
angular.module('app')
.factory('appConfig', function () {
return process.env.APP_CONFIG;
});
I have multiple sets of js modules that I would like to concat into separate files. I don't want to have to create a seperate concat task for each file. It would make more sense to be able to pass arguments into the gulp task "concat". Unfortunately gulp doesn't allow arguments to be passed into tasks(I'm sure for good reason).
Any ideas of how I can accomplish this?
Use Case
A specific scenario would be website that has a global.js file for all pages as well as page specific js files.
Creating a task for each page specific js file will quickly make the gulpfile.js hard to manage as the site grows.
My dev invironment:
I have a dev/js/ directory which has multiple sub-directories. Each sub-directory contains modules for a specific js file. So each sub-directory needs to be concatenated into it's own file within lib/js/.
Perhaps requirejs?
Maybe I should just look into using a module loader like requirejs.
I needed to take modules from my source sub-directory (src/modules/), concatenate a specific file to each individually (src/distribution), then pipe the result to a sub-directory in my distribution folder (dist/js/modules/).
I wasn't sure how many modules would end up being written for this project so I wanted to do it dynamically and found this to be the best (simplest) solution:
gulp.task("modules:js", () => {
let modules = fs.readdirSync("src/modules");
let concatModule = (module) => {
return gulp.src([
'src/distribution',
module
])
.pipe(concat(module))
.pipe(gulp.dest("build/js/modules"));
}
for (let module of modules) {
concatModule(module);
};
});
You could make concatJS a higher-order function:
var concatJS = function (src, filename, dest) {
return function() {
gulp.src(src)
.pipe(concat(filename))
.pipe(gulp.dest(dest));
};
};
gulp.task('concat-1', concatJS('src/module-1', 'module-1.js', 'build/module-1'));
gulp.task('concat-2', concatJS('src/module-2', 'module-2.js', 'build/module-2'));
//etc...
Note: You'd probably be better off using a bundler like browserify or webpack. Since asking this question I have switched to browserify rather than trying to roll my own solution.
Improved Solution:
var fs = require("fs");
/* other requires omitted */
/* Set JS dev directory in one place */
var jsSrc = "dev/js/";
var jsDest = "lib/js/";
var concat = function (path) {
path = path.replace(/\\/g, "/");
var src = path.replace(/(\/[^\/]+?\.js$)|(\/$)/, "/*.js";
var filename = src.match(/\/([^\/]+?)(\/[^\/]+?\.js$)/)[1] + ".js";
gulp.src(src)
.pipe(concat(filename)
.pipe(gulp.dest(jsDest));
});
/* The concat task just runs the concat function for
* each directory in the javascript development directory.
* It will take a performance hit, but allows concat to be
* run as a dependency in a pinch.
*/
gulp.task("concat", function () {
var dirArr = fs.readdirSync(jsDev);
for (var d in dirArr) {
var path = jsDev+dirArr[d]+"/";
concat(path);
}
});
/* Run "concat" as a dependency of the default task */
gulp.taks("default", ["concat"], function () {
var JSWatcher = gulp.watch([jsSrc+"**/*.js"]);
JSWatcher.on("change", function (event) {
concat(event.path);
});
});
Alright, I think this works. It's a little bit of a hack though, and doesn't work for all use cases.
... removed previous example to save space ...