Bundle .js and .css dependecies from package.json with gulp - javascript

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?

Related

Include new module installed using npm install

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.

gulp-rev creates a directory inside the destination directory

First of all, I would like to say that Gulp (for me) is creating more problems instead of solving them.
I wrote a gulpfile that concat some CSS files and put them inside a directory. The code for this task is the following:
var config = {
mainDir: 'app/assets'
};
config.stylesFiles = [
'bower_resources/admin-lte/dist/css/AdminLTE.min.css',
'bower_resources/admin-lte/dist/css/skins/_all-skins.min.css',
'css/app.css'
];
....
gulp.task('styles', function() {
return gulp
.src(config.stylesFiles, { cwd: config.mainDir })
.pipe(sourcemaps.init())
.pipe(concat('theme.css'))
.pipe(sourcemaps.write('../build/css'))
.pipe(gulp.dest('public/css/'))
.on('end', function() { gutil.log('Styles copied') });
});
It is very simple and works perfectly.
But, I would like to version this generated file. So I wrote a specific task to do it:
....
config.manifestFolder = process.cwd() + '/public/build';
gulp.task('versionCSS', function() {
return gulp
.src(['css/theme.css'], { cwd: 'public' })
.pipe(rev())
.pipe(gulp.dest('public/build/css'))
.pipe(rev.manifest(
{
base: config.manifestFolder,
cwd: config.manifestFolder,
merge: true
}
))
.pipe(gulp.dest(config.manifestFolder))
.on('end', function() { gutil.log('CSS files versioned') });
});
The problem is: when Gulp is going to run this task, it creates a folder inside the destination folder.
After running Gulp, I get this structure:
- public
- build
- css (destination folder for the versioned file)
- css (folder created by Gulp)
- versioned file that should be in the parent folder
- css
- concatenated file without version
I really don't know what to do anymore. I've already set the cwd and base options for the dest and src functions, changed the destinations, synchronized the tasks, etc. Nothing solves this stupid behavior.

Use gulp for typescript compilation

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...

gulp pipe(gulp.dest()) does not create any results

i am currently learning about gulp.js.
as i saw the tutorial and documentation of gulp.js, this code:
gulp.src('js/*.js')
.pipe(uglify())
.pipe(gulp.dest('minjs'));
makes the uglified javascript file with create new directory named 'minjs'. of course, i installed gulp-uglity with --dev-save option. there is no error message on the console so i don't know what is the problem. i tried gulp with "sudo", but still not working.
so i went to the root directory and searched all filesystem but there is no file named 'minjs' so i guess it just not working. why this is happening? anyone knows this problem, it would be nice why this is happening.
whole source code:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
gulp.task('default', function() {
console.log('mifying scripts...');
gulp.src('js/*.js')
.pipe(uglify())
.pipe(gulp.dest('minjs'));
});
I had the same problem; you have to return the task inside the function:
gulp.task('default', function() {
return gulp.src("js/*.js")
.pipe(uglify())
.pipe(gulp.dest('minjs'));
Also, minjs will not be a file, but a folder, where all your minified files are going to be saved.
Finally, if you want to minify only 1 file, you can specify it directly, the same with the location of the destination.
For example:
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var uglify = require('gulp-uglify');
gulp.task('browserify', function() {
return browserify('./src/client/app.js')
.bundle()
// Pass desired output filename to vinyl-source-stream
.pipe(source('main.js'))
// Start piping stream to tasks!
.pipe(gulp.dest('./public/'));
});
gulp.task('build', ['browserify'], function() {
return gulp.src("./public/main.js")
.pipe(uglify())
.pipe(gulp.dest('./public/'));
});
Hope it helps!
Finally I resolved the question like this:
It was a directory mistake so the gulp task hasn't matched any files; then it couldn't create the dest directory (because no files in output).
const paths = {
dest: {
lib: './lib',
esm: './esm',
dist: './dist',
},
styles: 'src/components/**/*.less',
scripts: ['src/components/**/*.{ts,tsx}', '!src/components/**/demo/*.{ts,tsx}'],
};
At first my scripts was ['components/**/*.{ts,tsx}', '!components/**/demo/*.{ts,tsx}']
And that hasn't matched any files.

Webstorm debugging with source maps from Browserify and Typescript

My project is a Laravel site, and I have the public folder renamed to "html". So my public files look like:
html
--js
----main.ts
And html is technically the root of the site for debugging purposes.
Using browserify, I have now generated some source maps for bundle.js, which have paths for main.ts. The problem is that they are pointing to the full path:
"html/js/main.ts"
Usually, I can run configurations to the html folder and catch breakpoints.
http://myapp.app:8000 ->> project>html
But this is not hitting breakpoints, since the html folder doesn't really exist in this setup. What's strange is that I can set break points in Chrome tools and it works. How can I set up Webstorm so it will hit break points in the html folder?
EDIT:
I am using the following gist for my source maps.
/**
* Browserify Typescript with sourcemaps that Webstorm can use.
* The other secret ingredient is to map the source directory to the
* remote directory through Webstorm's "Edit Configurations" dialog.
*/
'use strict';
var gulp = require('gulp'),
browserify = require('browserify'),
tsify = require('tsify'),
sourcemaps = require('gulp-sourcemaps'),
buffer = require('vinyl-buffer'),
source = require('vinyl-source-stream');
var config = {
client: {
outDir: './public/scripts',
out: 'app.js',
options: {
browserify: {
entries: './src/client/main.ts',
extensions: ['.ts'],
debug: true
},
tsify: {
target: 'ES5',
removeComments: true
}
}
}
};
gulp.task('client', function () {
return browserify(config.client.options.browserify)
.plugin(tsify, config.client.options.tsify)
.bundle()
.on('error', function (err) {
console.log(err.message);
})
.pipe(source(config.client.out))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('./', {includeContent: false, sourceRoot: '/scripts'}))
.pipe(gulp.dest(config.client.outDir));
});
I fixed it in Webstorm. The correct remote url for the html folder in run configurations is:
http://myapp.app:8000/js/html
Pretty weird, but Webstorm thinks that /js/html is a folder and that the source files are inside there.
EDIT 1 :Let me edit this answer. It turns out that the snippet above wasn't giving me all of the source maps. When inspecting the map file, the sources were being listed as js files and not ts files, which meant that the debugger wouldn't catch break points.
Here is the working gulp task, which watches any Typescript file for changes (as long as it's a dependency of main.ts and triggers browserify and the new sourcemaps. It requires the tsify plugin.
'use strict';
var watchify = require('watchify');
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var gutil = require('gulp-util');
var sourcemaps = require('gulp-sourcemaps');
var assign = require('lodash.assign');
// add custom browserify options here
var customOpts = {
entries: ['./html/js/main.ts'],
debug: true
};
var opts = assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts));
gulp.task('bundle', bundle); // so you can run `gulp js` to build the file
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
b.plugin('tsify')
function bundle() {
return b.bundle()
// log errors if they happen
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
// optional, remove if you dont want sourcemaps
.pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file
// Add transformation tasks to the pipeline here.
.pipe(sourcemaps.write({includeContent: false, sourceRoot: './'})) // writes .map file
.pipe(gulp.dest('./html/js'));
}

Categories