I am trying to learn about technologies including Grunt, Gulp, Webpack, Browserify, but I did not feel that there is much difference between them.
In other words, I feel Webpack can do everything that a task runner does. But still I got a huge examples where gulp and webpack are used together. What's the reason?
I might be taking things in the wrong direction. Am I missing anything? If so, what?
Grunt and Gulp are actually task runners, and they have differences like config driven tasks versus stream based transformations. Each has its own strengths and weaknesses, but at the end of the day, they pretty much help you create tasks that can be run to solve a larger build problem. Most of the time, they have nothing to do with the actual run-time of the app, but rather they transform or they put files, configs and other things in place so that the run time works as expected. Sometimes they even spawn servers or other processes that you need to run your app.
Webpack and Browserify are package bundlers. Basically, they are designed to run through all of a package's dependencies and concatenate their source into one file that (ideally) can be used in a browser. They are important to modern web development, because we use so many libraries that are designed to run with Node.js and the v8 compiler. Again, there are pros and cons and different reasons some developers prefer one or the other (or sometimes both!). Usually the output bundles of these solutions contain some sort of bootstrapping mechanisms to help you get to the right file or module in a potentially huge bundle.
The blurred line between runners and bundlers might be that bundlers can also do complex transformations or trans-pilations during their run-time, so they can do several things that task runners can do. In fact, between browserify and webpack there's probably around a hundred transformers that you can use to modify your source code. For comparison, there's at least 2000 gulp plugins listed on npm right now. So you can see that there are clear (hopefully... ;)) definitions of what works best for your application.
That being said, you might see a complex project actually using both task-runners and package bundlers at the same time or in tandem. For example at my office, we use gulp to start our project, and webpack is actually run from a specific gulp task that creates the source bundles that we need to run our app in the browser. And because our app is isomorphic, we also bundle some of the server code.
In my humble opinion, you might want to get familiar with all of these technologies because chances are you will see (use) all them in the course of your career.
I've just created my own task runner/bundler.
It's simpler to use than gulp and probably webpack (although I've never used webpack).
It's very simple and has babel, browserify, uglify, minify, and handlebars out of the box.
The syntax looks like this:
const Autumn = require("autumn-wizard");
const w = new Autumn();
//----------------------------------------
// CSS
//----------------------------------------
var cssFiles = [
'./lib/pluginABC/src/css/**/*.{css,scss}',
];
w.forEach(cssFiles, srcPath => {
var dstPath = w.replace('/src/', '/dist/', srcPath);
dstPath = w.replace('.scss', '.css', dstPath);
dstPath = w.replace('.css', '.min.css', dstPath);
w.minify(srcPath, dstPath, {
sourceMap: useSourceMap,
});
});
//----------------------------------------
// BUNDLE THE JS MODULE
//----------------------------------------
var srcPath = "./lib/pluginABC/src/main.js";
var dstPath = "./lib/pluginABC/dist/bundled.min.js";
w.bundle(srcPath, dstPath, {
debug: useSourceMap,
});
//----------------------------------------
// CREATE THE HANDLEBARS TEMPLATES
//----------------------------------------
var tplPaths = [
"./lib/pluginABC/src/templates/**/*.hbs",
];
dstPath = "./lib/pluginABC/dist/templates/bundled.js";
w.precompile(tplPaths, dstPath);
And the doc is here: https://github.com/lingtalfi/Autumn
Hopefully it helps.
Related
For a new project I am bound to keep things webpack-only, and thus need to find a way to efficiently compile our stylesheets. Basically in a very gulh-ish way:
gather all less-files including glob-patterns like src/**/*.less (css order may be arbitrary)
also allow import of css files like, say ../node_modules/vendor/**/*.css or 3rdparty/master.less
(If I have to setup a bogus.js entry point for that, fine...)
And with all of that, a typical gulp workflow:
transpile less to css
merge (concat) less and css
have cssnano do its optimization job, with specific css nano options like e.g. orderedValues: false, normalizeWhitespace: true ...
write styles.css as final output
And of course:
have source-maps survive that chain for a styles.css.map
efficient watching and the usual lazy/incremental compilation (as gulp and webpack have it)
Something I do not need is css modules (css imported into node modules for 'scoped' use, coming out as hash-scoped selectors...)
How can a 'typical' less|css-processing toolchain be done in Webpack?
This SO question has my first attempt where I got stuck in config hell right in the middle after combining...
considerations so far (helpful or not)
I know, to webpack, any ressource including css or even font and images is a "module"... Rather than merging my css 'modules' with with actual js (only to later painstakingly separate them again later again), it might be wiser, to have an entry point cssstub.js in parallel – also known as multi-compiler mode.
But that's really, where my wisdom ends... doing a sequence of $things on a set of files in webpack seems really hard (unless it's a connected javascript module graph). I did find something on globbing, but that's not enough (merge css, cssnano,...) and mostly I simply can't glue the pieces together...
I have used gulp to build less and create corresponding maps like below:
First step compiles less and generated css in tmp folder
gulp.task('compile-less', function () {
gulp.src('./*.less') // path to your file
.pipe(less().on('error', function(err) {
console.log(err);
}))
.pipe(gulp.dest('./tmp/'));
});
Second step minifies generated css and create map files
gulp.task('build-css', ['clean'], function() {
return gulp.src('./tmp/**/*.css')
.pipe(sourcemaps.init())
.pipe(cachebust.resources())
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('./compiled/css'));
});
If you want you can add additional step to conact generated css.
I am working on a website with React.js and asp.net mvc 4, I am planning to use Flux as my front-end architecture, but I met some problems and was very confused about the use of Flux:
In the beginning,I thought Flux would be a perfect front-end architecture in my website,but after I read a lot of articles about Flux, I find that they are nearly all with NodeJs,even the demos from facebook team,that means they all do the rendering stuffs of React.js/Flux code in server side,right? but How can I use Flux in the client side ,I mean in the user's browser?
I am very confused,am I wrong if I treat react.js/flux as a client side solution?If I am not wrong, but why they all use them with NodeJs and ES6(like facebook Dispatcher.js), That's ok in server side,but what about client side ? most of user broswers don't support ES6. I tried using Babel to convert Dispatcher.js from ES6 to ES5,but the es5 version had some errors and didn't work.
And I also found some implements of Flux that claim to support client side,like fluxxor,but I don't have a chance to try it before I write this post,because I am too confused.
I hope someone can help me to figure out these problems.
ps. Sorry for my english,if you don't understand my words,pls let me know , I will explain it.
I think you want :
$ bower install flux
Then you could do something like this (if using require.js):
require(
['bower_components/flux/dist/Flux'],
function(
Flux )
{
var dispatcher = new Flux.Dispatcher();
dispatcher.register(function(payload) {
if (payload.actionType='test') {
console.log('i got a ', payload);
}
});
dispatcher.dispatch({
actionType: 'test',
otherData: { foo: 'bar' }
});
});
(This answer uses : https://bower.io/, https://libraries.io/bower/flux, http://requirejs.org/)
React is a client side library. You can serve a React App with virtual any backend language. The reason a lot of examples are with node is because it is easy and fast to set up.
You should try this tutorial:
https://facebook.github.io/react/docs/getting-started.html
It is pretty straight forward and doesn't require node.
Also maybe you should try starting to serve the React app statically at the beginning to better understand React itself.
ES6 works in Browsers thanks to Babel. If you believe you have any trouble with Babel, you might want to first play around with it's REPL to get a feeling for it: https://babeljs.io/repl/
The idea is that the code can run on the client and server (universal js, used to be called isomorphic javascript (though it goes a little further then that with serverside rendering etc..),
There are many flux implementations reflux is the most promising at this point , im using martyjs (but they stopped the development, it will be taken over by alt) but even for the flux architecture, u just get the dispatcher / event emitter and some ideas :D,
Shorty said u can install the npm packages (flux, react , babel) etc, but u need something like http://browserify.org/(with reactify) or Webpack, to run them in the browser. U don't need to run them on a node js "after its bundled", webpack/browserify will bundle the code so it can used within the browser independently
https://github.com/christianalfoni/flux-react-boilerplate/ <-- ther are some boilerplate, that provide some nice guide on how to bundle the code.
I know that L5 and Elixir are still under development, but I'm excited to start thinking about ways to reorganize my code. I think my question has more to do with asset management, in the context of L5 and Elixir.
Want to clarify how concatenation and versioning should be handled (in my case I'm using Elixir's styles() and version()). The issue I'm having is that the new file after concat/version will be located in a new folder, breaking any references to assets from the original css or js files.
For example, an original CSS file that has background-image: url('../img.png') will no longer work. I've tried a couple of things, but both are not ideal especially in the case of vendor plugins:
Move required assets over one-by-one (using mix.copy() for each folder of assets), to the new build path (ie. the build path used by Elixir's versioning).
Manually edit the paths in each asset file to refer to an absolute path
Although both of these options will make things work, I feel as though I may be missing something. It also becomes quite impractical when working with javascript plugins (ex. ones that come with their own images, fonts, stylesheets, etc).
Is there a more practical way of managing relative paths when concatenating and versioning?
Here is the solution for Laravel Elixir after you build for versioning.
For copy command you need reference it as full path.
var elixir = require('laravel-elixir');
/*
|--------------------------------------------------------------------------
| Elixir Asset Management
|--------------------------------------------------------------------------
|
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
| for your Laravel application. By default, we are compiling the Less
| file for our application, as well as publishing vendor resources.
|
*/
elixir(function(mix) {
mix.version('themes/default/assets/css/styles.css')
.copy('public/themes/default/assets/img/', 'public/build/themes/default/assets/img/');
});
EDIT:
I just submitted a pull request to Elixir, so you can just do:
mix.version(
['css/style.css', 'css/vendor/style.css'], //files to be versioned
['fonts', 'css/vendor/icons'] //dependent files/dirs to be copied
);
OLD ANSWER:
Actually, if you use mix.copy(...) alone, you just can't use gulp watch and you'll need to recompile your entire stack in order to get this working.
You can achieve the same results with the solution below and don't need to recompile everything, because it'll just work when you change a versioned file:
var shell = require('gulp-shell');
gulp.task('cp', shell.task(['cp -R public/fonts public/build/',
'cp -R path/to/vendor/dir public/build/vendor/',
'... etc ...']));
elixir(function(mix) {
...
//register a watcher to run 'cp' when you rebuild
mix.task('cp','public/build/**/*.(js|css)');
}
They are relative paths - so keep the relative relationship.
Just move the images over to the public/build/ directory as part of the gulp command, after the visioning.
I am using the docpad-plugin-grunt with several grunt tasks. I wonder what is the best way to run tasks over all docpad generated html documents without individual files to be specified in the gruntfile.js. Is there a routine where docpads handing over to grunt all filenames? Can dopad handle the iteration or is a seperated script needed?
I don't think grunt is the way to go for this, what you really want to do is hook in to the rendering process that docpad does for each document. Typically, grunt is used to run a task at the end of the generation to do something that docpad doesn't do out of the box.
To intercept docpad's rendering process you probably want to handle the docpad render event which you define in the events section of the docpad.coffee file.
Assuming you want to minify your html you might do something like this (more or less lifted from the docpad documentation):
render: (opts) ->
# Prepare
{inExtension,outExtension,templateData,file,content} = opts
docpad = #docpad
# Render if applicable
if outExtension in ['html']
opts.content = minifyFunction(content)
app.use(express.compiler({ src: __dirname + '/public', enable: ['less'] }));
That's the line in my app.js that enables less. How can I pass the { compress: true } parameter to it?
I also had this problem and thought this can be useful to share with others:
var lessMiddleware = require('less-middleware');
app.use(lessMiddleware({ src: __dirname + '/public', compress: true, optimization: 2 }));
More information and settings about the minify-process can be found in the Less-Middleware README.md
use less4clients with the compress option
I deprecated and removed the less4clients package which extends a express.js server with a less css rendering middleware to render less files to css on the fly (and cache the results in memory) in favor of a newer project of mine called DocPad that lets you use any pre-processor you want.
As of this time of writing, it does not have an easy to use express middleware like less4clients, however such a thing is on the roadmap soon. Instead you can use it standalone or via its API.
In hindsight I should have kept less4clients available and just stated in it's readme that DocPad is the new way of doing things, but I never realised less4clients was actually being used by anyone as DocPad has already gained so much attention.
Sadly, you can't and use connect's compiler to do it. The connect.compiler, which is what express.compiler is, only allows you to set which compilers to use, but not any options for the individual compilers. If you want to set less.js's compress flag you will need to create you're own middleware that user the less.js module.