I'm working on a project that uses Node and Gulp, and I want to add a new Javascript library for some new features in the site.
I found this library that does what I need: http://imakewebthings.com/waypoints/
It says in the library website that I need to run npm install waypoints, so I did just that, and a new waypoints directory was created in my node_modules directory. Then I'm said to include the new library in my project like this:
<script src="/path/to/noframework.waypoints.min.js"></script>
But, the library is one level above the document root of my project, so I can't just do src="/node_modules/waypoints/src/waypoint.js" because that folder is not reachable from the web browser.
I tried to add the new module to the gulpfile.js file of my project but it still doesn't work.
var waypoints = require('waypoints'),
I still get a "Uncaught ReferenceError: Waypoint is not defined" error.
What am I missing? How do I get node and/or gulp to load this new library?
EDIT
This is what I have in my gulpfile.js where I "think" it's including the libraries for use in the client side:
var customJSScripts = ['src/js/custom/**/*.js'];
var libsJSscripts = ['src/js/libs/**/*.js'];
var allJSScripts = ['src/js/**/*.js'];
var outputFileName = 'custom.min.js';
var outputFolder = './dist/js/'
gulp.task('jshint', function() {
return gulp.src(customJSScripts)
.pipe(jshint({'esversion': 6}))
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('concat-scripts', function() {
if (envVars.minifyJS) {
gulp.src(customJSScripts)
.pipe(sourcemaps.init())
.pipe(concat(outputFileName))
.pipe(uglify())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(outputFolder));
} else {
gulp.src(customJSScripts)
.pipe(sourcemaps.init())
.pipe(concat(outputFileName))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(outputFolder));
}
gulp.src(libsJSscripts)
.pipe(sourcemaps.init())
.pipe(concat('libs.min.js'))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(outputFolder))
});
You don't need to require() waypoints, since you are not using it on the server. What you should do is add another task and make it a dependency for concat-scripts like below:
gulp.task('move-waypoint', function() {
var required_files = [
'../node_modules/waypoints/waypoints.min.js' //make sure this is the right path
];
return gulp.src(required_files, {base: '../node_modules/waypoints/'})
.pipe(gulp.dest(outputFolder));
});
gulp.task('concat-scripts', ['move-waypoint'],function() { //will execute the move-waypoint task first
//your usual code here...
});
You can then look at the path of waypoint in the output folder to determine the script path to include in your html page.
Related
I'm trying to convert an old project that uses Bower + gulp (+ npm) into something similar, which doesn't use Bower but keeps most of Gulp.
I'm stuck with reproducing the equivalent of wiredep, ie, picking all the relevant .js and .css from third party dependencies (which now are moved from Bower to package.json), to use them for either HTML injection or bundling all .js/.css into a single file.
Before, it was doing this, using a mix of wiredep and inject:
gulp.task('inject-html', ['compile-styles'], function () {
$.util.log('injecting JavaScript and CSS into the html files');
var injectStyles = gulp.src(config.outputCss, { read: false });
var injectScripts = gulp.src(config.js, { read: false });
var wiredepOptions = config.getWiredepDefaultOptions();
var injectOptions = {
ignorePath: ['src', '.tmp'], addRootSlash: false,
};
var wiredep = require('wiredep').stream;
return gulp.src(config.html)
.pipe(wiredep(wiredepOptions))
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(gulp.dest(config.srcDir), {overwrite: true});
});
Now, I've managed to do this for the .js files:
gulp.task('bundle-deps', function () {
var deps = Object.keys(packageJson.dependencies)
.map(module => `node_modules/${module}/**/*.js`);
// set up the browserify instance on a task basis
var b = browserify({
entries: './package.json',
debug: true
});
return b.bundle()
.pipe(source('genemap-lib.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true})) // debug info for the browser
.pipe(uglify())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./dist/js/'));
});
This works in building a single dependency .js. That's not like the injection above, but I'd be fine with it.
However, I can't find any way to do the same for the .css files, because this:
gulp.task('bundle-deps-css', function () {
var deps = Object.keys(packageJson.dependencies);
var depsCss = deps.map(module => `node_modules/${module}/**/*.css`);
return gulp.src( depsCss )
.pipe(concatCss("genemap-lib.css"))
.pipe(gulp.dest('dist/styles/'));
});
picks up some */demo/demo.css and then I get the error that it has a syntax error.
I'm thinking that the above methods are wrong, selecting all .js/.css is too dumb, there should be a way to select the library-exported files, not all that can be found in its directory (ie, the gulp equivalent of wiredep).
But how to do it? Is it possible with Gulp? Should I migrate to something like webpack? And Yarn too?
So I have a simple use case, and it seems very similar to the usecase described in the readme for https://github.com/jonkemp/gulp-useref.
I'm trying to generate a templates.js file with all of the Angular templates during the build. I am trying to do this and NOT have a templates.js file in my local project. So the idea was to merge the output of the template stream into the useref stream so that the resulting scripts.js file would contain all of the files indicated in my index file AND the generated templates ouput.
Here's what I have in the gulp task:
gulp.task('usemin:dist', ['clean:dist'], function() {
var templatesStream = gulp.src([
'./app/**/*.html',
'!./app/index.html',
'!./app/404.html'
]).pipe(templateCache({
module: 'myCoolApp'
}));
var assets = $useref.assets({
additionalStreams: [templatesStream]
});
return gulp.src('./app/index.html')
.pipe(assets)
.pipe(assets.restore())
.pipe($useref())
.pipe(gulp.dest('./dist/'));
});
Now this should allow me to merge the output of the templatesStream and turn it all into one scripts.js file, I think...
I've also tried having <script src="scripts/templates.js"></script> of many forms sitting in my index file to try and assist it. None seem to work.
Anyone else doing this same type of thing? Seems like a common use-case.
I was able to get this to work by looking closely at the test cases.
I now have a templates.js script tag on my index.html file which will 404 while in my local environment.
My gulp task looks like this:
gulp.task('useref:dist', ['clean:dist'], function() {
var templateStream = gulp.src([
'./app/**/*.html',
'!./app/index.html',
'!./app/404.html'
]).pipe(templateCache({
module: 'digitalWorkspaceApp'
}));
var assets = $useref.assets({
additionalStreams: [templateStream]
});
var jsFilter = $filter('**/*.js', {restore: true});
return gulp.src('./app/index.html')
.pipe(assets)
.pipe($useref())
.pipe(gulp.dest('./dist/'));
});
Immediately I can't really see the difference, but it may have all hinged on the addition of this non-existent file in my index.html.
I have an app built with Node-Gulp-Webpack.
I have an external JavaScript file external.js that is not local to my app, but I want to be able to require it in my app. This file is on a path for which there is an environment variable named MY_PATH.
How can I include this external.js as-is in my build without making a Node module out of it?
So far, this does not work and doesn't return a useful error message:
var external = require(process.env.MY_PATH + '/external.js');
Use gulp-remote-src, the example:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var remoteSrc = require('gulp-remote-src');
gulp.task('remote', function() {
remoteSrc(['app.js', 'jquery.js'], {
base: 'http://myapps.com/assets/',
})
.pipe(uglify())
.pipe(gulp.dest('./dist/'));
})
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'm extremely new to Gulp. I'm basically trying to watch for a modified JavaScript file, and then make a new copy of it with a new name. (eventually there'll be some processing on it, but Rome wasn't built in a day).
My (naive) attempt is this:
gulp.task('default', function() {
return gulp.watch('../**/**.js', function(obj){
gulp.src(obj.path)
.pipe(gulp.dest('foobar.js'));
});
});
This takes the modified file and successfully copies it into a folder now called foobar.js. Is there anything simple I can replace gulp.dest('foobar.js') with that will simply copy and rename the src file in place?
EDIT
By copy in place, I mean I want to take the modified file, and make a copy of it right where it currently is with a new name. The equivalent of clicking the file (in windows) and hitting control-c control-v, then renaming the resulting file.
I'm not 100% certain what you mean by
copy and rename ... in place
But, based on your current code, if you simply wish to:
Watch all .js files in the parent directory and
Copy them to the cwd (current working directory) and
Name all copies, regardless of source file, the same thing
Then you could use gulp-rename to do just that:
var gulp = require('gulp');
var rename = require('gulp-rename');
gulp.task('default', function() {
return gulp.watch('../**/**.js', function(obj) {
gulp.src(obj.path)
.pipe(rename('newFileName.js'))
.pipe(gulp.dest('.'));
});
});
In this case, the output filename is newFileName.js
In order to use the module, you'll need to install the gulp-rename package with npm (ie: npm install gulp-rename).
More examples are available on the package details page on npm # https://www.npmjs.com/package/gulp-rename#usage
It wasn't pretty getting there, but in the end it appears this is what I want (with some ES6 transpiling in the middle).
The key appears to be the options object with a base property in the call to src. That seems to be what's needed to maintain the path of the current file in the call to dest.
var gulp = require('gulp'),
rename = require('gulp-rename'),
babel = require('gulp-babel');
gulp.task('default', function() {
return gulp.watch('../**/$**.js', function(obj){
if (obj.type === 'changed') {
gulp.src(obj.path, { base: './' })
.pipe(babel())
.pipe(rename(function (path) {
path.basename = path.basename.replace('$', '');
}))
.pipe(gulp.dest(''));
}
});
});
20 lines of code to do 'cp file1 file2'
That's elegance.