I'm trying to add livereload to broccoli
Unfortunately the live-reload plugin documentation is a bit short and I cannot get it to work. In the docs it is stated to do the following:
var injectLivereload = require('broccoli-inject-livereload');
var public = injectLivereload('public');
I figured that this should be placed inside the Brocfile.js (right?). But whatever I do nothing gets reloaded (I have to hit reload to refresh) I've also changed the 'public' part, which I think is representing a directory. Any help would be appreciated.
I'm using BrowserSync instead of "only" LiveReload. It also supports LiveReload (and LiveInject for CSS), but it has tons of other features as well (like ghosting).
Let's create a file called server.js and a folder called app next to it, where you put our index.html, .css and .js. This server.js contains:
var broccoli = require("broccoli");
var brocware = require("broccoli/lib/middleware");
var mergeTrees = require("broccoli-merge-trees");
var Watcher = require("broccoli-sane-watcher");
var browserSync = require("browser-sync");
var tree = mergeTrees(["app"]); // your public directory
var builder = new broccoli.Builder(tree);
var watcher = new Watcher(builder);
watcher.on("change", function(results) {
if (!results.filePath) return;
// Enable CSS live inject
if (results.filePath.indexOf("css") > -1) {
return browserSync.reload("*.css");
}
browserSync.reload();
});
browserSync({
server: {
baseDir: "./",
middleware: brocware(watcher)
}
});
Now fire the server (which will open the browser automatically):
node server.js
I know this isn't as straightforward as Gulp or Grunt at first sight, but it offers fine grained control over everything and it's really blazing fast, even if your app grows and grows.
Instead of Livereload I opted to use Browsersync via the Broccoli Browser Sync plugin
My final Brocfile.js was very similar to (pulled from plugins npm page):
var fastBrowserify = require('broccoli-fast-browserify');
var babelify = require('babelify');
var mergeTrees = require('broccoli-merge-trees');
var compileSass = require('broccoli-sass-source-maps');
var funnel = require('broccoli-funnel');
var BrowserSync = require('broccoli-browser-sync');
var optionalTransforms = [
'regenerator'
// 'minification.deadCodeElimination',
// 'minification.inlineExpressions'
];
var babelOptions = {stage: 0, optional: optionalTransforms, compact: true};
// var browserifyOpts = {deps: true, entries: files, noParse: noParse, ignoreMissing: true};
var transformedBabelify = fastBrowserify('app', {
browserify: {
extensions: [".js"]
},
bundles: {
'js/app.js': {
entryPoints: ['app.js'],
transform: {
tr: babelify,
options: {
stage: 0
}
}
}
}
});
var appCss = compileSass(['piggy/frontend/app'], 'main.scss', 'css/app.css');
var staticFiles = funnel('frontend', {
srcDir: 'static'
});
var browserSync = new BrowserSync([staticFiles, transformedBabelify, appCss]);
module.exports = mergeTrees([staticFiles, transformedBabelify, appCss, browserSync]);
With this solution I was able to continue using broccoli to serve my assets via broccoli serve and all my assets would be rebuilt then reloaded in the browser including my css.
Related
I am a beginner to Javascript and Gulp. Am learning this based on a udemy course in which Gulp 3 is being used, and I've been looking at docs to convert the code to Gulp 4. It's been fun so far since I am learning more when I am doing the conversions myself, but am stuck on this one. Wonder if you guys can offer some advice.
Issue: When I split the gulpfile.js into separate files to organise my files better, it starts throwing errors. Code below.
styles.js
var gulp = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
function styles(cb) {
return gulp.src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(gulp.dest('./app/temp/styles'));
cb();
}
exports.styles = styles;
watch.js
var gulp = require('gulp'),
browserSync = require('browser-sync').create();
function cssInject(cb) {
return gulp.src('./app/temp/styles/styles.css')
.pipe(browserSync.stream());
cb();
}
function browserSyncReload(cb) {
browserSync.reload();
cb();
}
function watch(cb) {
browserSync.init({
notify: false,
server: {
baseDir: "app"
}
});
watch('./app/index.html', browserSyncReload);
watch('./app/assets/styles/styles.css', gulp.series(cssInject, styles));
cb();
}
exports.browserSyncReload = browserSyncReload;
exports.watch = watch;
gulpfile.js
var stylesTasks = require('./gulp/tasks/styles.js'),
watchTasks = require('./gulp/tasks/watch.js');
exports.watch = watchTasks.watch;
exports.styles = stylesTasks.styles;
exports.browserSyncReload = watchTasks.browserSyncReload;
When I run "gulp watch", this is what I get.
error
$ gulp watch
[21:14:28] Using gulpfile ~/Projects/travel-site/gulpfile.js
[21:14:28] Starting 'watch'...
internal/async_hooks.js:195
function emitInitNative(asyncId, type, triggerAsyncId, resource) { ^
RangeError: Maximum call stack size exceeded
(Use `node --trace-uncaught ...` to show where the exception was thrown)
I found another post with almost identical code, but with a different error - which happened to be one of the errors i was getting earlier as well, and have followed the solution mentioned in that post - and that's when I get this error. Here's the link to the post.
Any help is much appreciated. Thanks for your time.
I have a full article that shows many how to regarding going from gulp3 to gulp4, I think you are going to find everything you need there
But basically, I think you need to take a look at these modules :
gulp-task-loader-recursive
gulp4-run-sequence
require-dir
Then, from a gulp.js perspective, you can end up with something like this :
// gulpfile.js
global.config = require('./gulp/config/config.json');
require('events').EventEmitter.prototype._maxListeners = 1000;
require('require-dir')('./gulp/tasks/styles');
require('require-dir')('./gulp/tasks/watch');
//... etc ...
So you would be able to then create your styles task and export it :
var gulp = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
function styles(cb) {
return gulp.src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(gulp.dest('./app/temp/styles'));
cb();
}
const stylesTask = task('styles', styles);
exports.stylesTask = stylesTask;
You can then validate its recognized by gulp :
gulp --tasks
If you correctly see your styles tasks, you should now be able to run your task by running :
gulp styles
Repeat those steps for the watch task.
Answering my own question feels wierd, but I found the solution after playing with it for couple of days. See below.
I needed to import styles into watch.js, and not gulpfile.js. That was my first mistake. To do this, I added the below line to watch.js
var styles = require('./styles').styles;
Then my gulpfile.js only needed two lines
gulpfile.js
var watchTask = require('./gulp/tasks/watch').watch;
exports.default = watchTask;
I also removed the variable gulp, instead created variables for src and dest. So, the rest of the code looked like below.
styles.js
var {src, dest} = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
const styles = function (cb) {
return src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(dest('./app/temp/styles'));
cb();
}
exports.styles = styles;
watch.js
var styles = require('./styles').styles;
var {src, series, watch} = require('gulp'),
browserSync = require('browser-sync').create();
const cssInject = function (cb) {
return src('./app/temp/styles/styles.css')
.pipe(browserSync.stream());
cb();
}
const reload = function (cb) {
browserSync.reload();
cb();
}
const watchTask = function (cb) {
browserSync.init({
notify: false,
server: {
baseDir: "app"
}
});
watch('./app/index.html', reload);
watch('./app/assets/styles/styles.css', series(cssInject, styles));
cb();
}
exports.watch = watchTask;
Hence resolved! hope this helps someone else.
I have an asp.net where I have an MVC application where I want to add some client side processing using TypeScript, and call this from a.cshtml file (just using plain JavaScript from within this page). I am bundling using Gulp and Browserify
I have the following gulp file
/*
Use gulp --production to minimize and skip source maps
This skips the bundling jquery , so need to include this before the bundle
*/
// Pass this to build in production
var PRODUCTION_ARG = "production";
// Itellisense related defines
var INTELLISENSE_SRC_FOLDER = "UserControls/Intellisense/src";
var INTELLISENSE_DEST_FOLDER = "UserControls/Intellisense/build";
var INTELLISENSE_BUNDLE_FILENAME = "intellisense-bundle.js";
var gulp = require('gulp');
var del = require('del');
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
var uglify = require('gulp-uglify');
var buffer = require('vinyl-buffer');
var argv = require('yargs').argv;
gulpif = require('gulp-if');
gulp.task('intellisense-clean', function () {
return del([INTELLISENSE_DEST_FOLDER + '/**/*']);
});
gulp.task("intellisense-copy-html", function () {
return gulp.src(INTELLISENSE_SRC_FOLDER + "/*.html")
.pipe(gulp.dest(INTELLISENSE_DEST_FOLDER));
});
gulp.task("intellisense-copy-css", function () {
return gulp.src(INTELLISENSE_SRC_FOLDER + "/*.css")
.pipe(gulp.dest(INTELLISENSE_DEST_FOLDER));
});
gulp.task("build-intellisense", ["intellisense-clean", "intellisense-copy-html", "intellisense-copy-css"], function () {
return browserify({
basedir: '.',
debug: true,
standalone: 'ABC',
entries: [INTELLISENSE_SRC_FOLDER + '/intellinode.ts',
INTELLISENSE_SRC_FOLDER + '/code-description-pair.ts',
INTELLISENSE_SRC_FOLDER + '/console-logger.ts',
INTELLISENSE_SRC_FOLDER + '/intellisense-control.ts'],
cache: {},
packageCache: {},
})
.ignore('jquery')
.plugin(tsify)
.bundle()
.pipe(source(INTELLISENSE_BUNDLE_FILENAME))
.pipe(buffer())
.pipe(gulpif(argv.production, uglify()))
.pipe(gulp.dest(INTELLISENSE_DEST_FOLDER));
});
gulp.task("default", ["build-intellisense"], function () {
});
My tsconfig.json is as follows..
{
"compilerOptions": {
"noImplicitAny": true,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es3",
"module": "commonjs"
},
"target": "es3",
"files": [
"./UserControls/Intellisense/src/*.ts"
],
"exclude": [
"node_modules",
"wwwroot"
],
"compileOnSave": true
}
The first weird thing is I seem to need to include each ts file in the entries: list for the call to browserify, otherwise I only seem to get one or 2 of the classes included in the output bundle file.
So, including them all seem to work (though would like to know why need them all and not just the "top level" one.
The next problem is that I want to instantiate and call some of the methods from plain browser JavaScript. From other posts, I am told I can use the standalone: 'Intellisense' flag as above. This then adds a global object "ABC" (which I can see int eh debugger) but only seems to include one of the TypeScript classes (infact the last one in the entries list)
I have changed the tsconfig module to amd but got other errors (so changed back to commonjs).
I really do not know where to go from here. Seems to be very limited doco on marrying the TypeScript world back into plain browser JavaScript world.
Any help here would be greatly appreciated!
From what I could find out, nothing bundled by Browerify can be accessed outside of what is bundled within it, i.e. none of the exports are accessible by any external JavaScript (this was what I was actually asking in the question). Browerify just makes the stuff within the bundle work within the Browser.
So to expose my class(es) outside you can just add an object to the global space and just add anything to this...
E.g. in the TS file have
(function () {
let w: any = window;
w.TSModule = {};
w.TSModule.CreateClassToExport = function() {
return new ClassToExport();
}
})();
export class ClassToExport {
public doWork() : void{
...
}
and in the .cshtml JavaScript include the bundle and just get access to this object as below...
var myExport = TSModule.CreateClassToExport();
myExport.doWork();
Yes this adds something to the global space which I know is bad, but it is only one object.
Still be interested if there are any better solutions, but at least I can now use my TS code.
I am trying to use the Broccoli Funnel package to pull a complete directory into my assets folder in an Ember CLI build. Please find my ember-cli-build.js file below:
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var Funnel = require('broccoli-funnel');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
//
});
var extraAssets = new Funnel('vendor/images/frames/artist/64', {
destDir: '/assets/images'
});
app.toTree(extraAssets);
return app.toTree();
};
The directory "vendor/images/frames/artist/64" only contains .png image files and I would like to have them all available after the build at "assets/images/64/". After a build process, there is no images folder created in my assets directory.
Can you help advise where I have gone wrong? Are there any debugging tools to show what Broccoli Funnel is trying to add to the build and where those files are being distributed to?
app.ToTree accepts an array of transformed nodes (trees in broccoli 1.x.x).
Also, you have to return the node transformed by your app.toTree call.
So instead of,
...
app.toTree(extraAssets);
return app.toTree();
You would do,
return app.toTree([extraAssets])
Like Lux suggests, using broccoli-merge-trees is encouraged.
var EmberApp = require('ember-cli/lib/broccoli/ember-app'),
Funnel = require('broccoli-funnel'),
MergeTrees = require('broccoli-merge-trees');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
//
}),
nodes = [];
nodes.push(new Funnel('vendor/images/frames/artist/64', {
destDir: '/assets/images'
}));
nodes.push(app.toTree());
return new MergeTrees(nodes);
};
Debugging Broccoli Trees/Nodes
For debugging your broccoli plugin output, use broccoli-stew. Here's a quick sample to list out the files that are present just after the Funnel step.
var EmberApp = require('ember-cli/lib/broccoli/ember-app'),
Funnel = require('broccoli-funnel'),
MergeTrees = requre('broccoli-merge-trees'),
log = require('broccoli-stew').log;
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
//
}),
loggedNode,
nodes = [];
funnelOutput = new Funnel('vendor/images/frames/artist/64', {
destDir: '/assets/images'
}));
nodes.push(log(funnelOutput))
nodes.push(app.toTree());
return new MergeTrees(nodes);
};
You should use MergeTrees:
return new BroccoliMergeTrees([app.toTree(), extraAssets]);
instead of
app.toTree(extraAssets);
return app.toTree();
I have a project with a few relatively disjoint pages, each including their own entry point script. These scripts require a number of others using commonjs syntax, and need to be transformed by 6to5 and bundled by browserify.
I would like to set up a gulp task that captures all the files matching a pattern and passes them on to the bundler, but I'm not sure how to pass files from gulp.src to browserify(filename).
My gulpfile looks like:
var gulp = require("gulp");
var browserify = require("browserify");
var to5browserify = require("6to5-browserify");
var source = require("vinyl-source-stream");
var BUNDLES = [
"build.js",
"export.js",
"main.js"
];
gulp.task("bundle", function () {
/* Old version, using glob:
return gulp.src("src/** /*.js")
.pipe(sixto5())
.pipe(gulp.dest("dist"));
*/
// New version, using array:
return BUNDLES.map(function (bundle) {
return browserify("./src/" + bundle, {debug: true})
.transform(to5browserify)
.bundle()
.pipe(source(bundle))
.pipe(gulp.dest("./dist"));
});
});
gulp.task("scripts", ["bundle"]);
gulp.task("html", function () {
return gulp.src("src/**/*.html")
.pipe(gulp.dest("dist"));
});
gulp.task("styles", function () {
return gulp.src("src/**/*.css")
.pipe(gulp.dest("dist"));
});
gulp.task("default", ["scripts", "html", "styles"]);
This seems to work, but isn't maintainable: I'll be adding more scripts relatively soon, and don't want to add them to the array every time.
I've tried using gulp.src(glob).pipe within the browserify call and piping after calling (shown here), and gulp.src(glob).map (method doesn't exist).
How can you chain gulp.src with a name-based transformer like browserify?
Use through2 to make a one-off custom plugin stream that does all of the dirty work.
Unfortanately vinyl-transform and vinyl-source-stream and the solutions that go along with those have flaws so we have to go for something custom.
var gulp = require('gulp');
var through = require('through2');
var browserify = require('browserify');
gulp.task('bundle', function() {
var browserified = function() {
return through.obj(function(chunk, enc, callback) {
if(chunk.isBuffer()) {
var b = browserify(chunk.path);
// Any custom browserify stuff should go here
//.transform(to5browserify);
chunk.contents = b.bundle();
this.push(chunk);
}
callback();
});
};
return gulp.src(['./src/**/*.js'])
.pipe(browserified())
.pipe(gulp.dest('dest'));
});
You can specify globs in your BUNDLES array as well as exclude any files:
var BUNDLES = [
"app/**/*.js",
"export.js",
"app/modules/**/*.js",
"!app/modules/excluded/*.js"
];
Im new to Gulp.. I have been able to successfully install and concatenate and minify my .js and .css files, however, there is one .css file which i want to exclude - print.css
Ive followed the instructions here: https://www.npmjs.org/package/gulp-ignore install gulp-ignore in my local directory, and modified my gulpfile.js to:
// Include gulp
var gulp = require('gulp');
// Include Our Plugins
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var minifyCSS = require('gulp-minify-css');
var imagemin = require('gulp-imagemin');
var exclude = require('gulp-ignore').exclude;
var paths = {
scriptsNonAuth: ['Non-Auth/javascript/*.js'],
scriptsAuth: ['Auth/javascript/*.js'],
stylesNonAuth: ['Non-Auth/css/*.css'],
stylesAuth: ['Auth/css/*.css'],
};
// CSS Task - Non Authenticated
gulp.task('minify-css-non-auth', function() {
gulp.src(paths.stylesNonAuth)
.pipe(minifyCSS(opts))
.pipe(concat('all.min.css'))
.pipe(gulp.dest('Non-Auth/css'))
});
// CSS Task - Authenticated
gulp.task('minify-css-auth', function() {
gulp.src(paths.stylesAuth)
.pipe(minifyCSS(opts))
**.pipe(exclude('Auth/css/print.css'))**
.pipe(concat('all.min.css'))
.pipe(gulp.dest('Auth/css'))
});
Within my CSS Task - Secure, i have included .pipe(exclude('Secure/css/print.css'))
When i run gulp minify-css-secure, the task completes but upon inspecting the new all.min.css, i cant see the contents of print.css within there too.
It's unclear what you are trying to achieve. If I get it right, you want to:
minify all css files (including print.css)
concat all files except print.css into all.min.css
put minified all.min.css and print.css into destination folder
To achieve that, you can use StreamQueue. (source)
var streamqueue = require('streamqueue');
var paths = {
scriptsNonAuth: ['Non-Auth/javascript/*.js'],
scriptsAuth: ['Auth/javascript/*.js'],
stylesNonAuth: ['Non-Auth/css/*.css'],
stylesAuth: ['Auth/css/*.css', '!Auth/css/print.css'],
};
gulp.task('minify-css-auth', function() {
return streamqueue({ objectMode: true },
gulp.src(paths.stylesAuth)
.pipe(minifyCSS(opts))
.pipe(concat('all.min.css')),
gulp.src('Auth/css/print.css'))
.pipe(minifyCSS(opts))
)
.pipe(gulp.dest('Auth/css'))
});
If you want to just exclude some files, you don't need gulp-ignore. Gulp supports ignore globs.
Just prefix the path to exclude with bang.
Like this:
stylesAuth: ['Auth/css/*.css', '!Auth/css/print.css']