NPM vs. Bower vs. Browserify vs. Gulp vs. Grunt vs. Webpack
I'm trying to summarize my knowledge about the most popular JavaScript package managers, bundlers, and task runners. Please correct me if I'm wrong:
npm
& bower
are package managers. They just download the dependencies and don't know how to build projects on their own. What they know is to call webpack
/ gulp
/ grunt
after fetching all the dependencies. bower
is like npm
, but builds flattened dependencies trees (unlike npm
which do it recursively). Meaning npm
fetches the dependencies for each dependency (may fetch the same a few times), while bower
expects you to manually include sub-dependencies. Sometimes bower
and npm
are used together for front-end and back-end respectively (since each megabyte might matter on front-end). grunt
and gulp
are task runners to automate everything that can be automated (ie compile CSS/Sass, optimize images, make a bundle and minify/transpile it). grunt
vs. gulp
(is like maven
vs. gradle
or configuration vs. code). Grunt is based on configuring separate independent tasks, each task opens/handles/closes file. Gulp requires less amount of code and is based on Node streams, which allows it to build pipe chains (w/o reopening the same file) and makes it faster. webpack
( webpack-dev-server
) - for me it's a task runner with hot reloading of changes which allows you to forget about all JS/CSS watchers. npm
/ bower
+ plugins may replace task runners. Their abilities often intersect so there are different implications if you need to use gulp
/ grunt
over npm
+ plugins. But task runners are definitely better for complex tasks (eg "on each build create bundle, transpile from ES6 to ES5, run it at all browsers emulators, make screenshots and deploy to dropbox through ftp"). browserify
allows packaging node modules for browsers. browserify
vs node
's require
is actually AMD vs CommonJS. Questions:
webpack
& webpack-dev-server
? Official documentation says it's a module bundler but for me it's just a task runner. What's the difference? browserify
? Can't we do the same with node/ES6 imports? gulp
/ grunt
over npm
+ plugins? Webpack and Browserify
Webpack and Browserify do pretty much the same job, which is processing your code to be used in a target environment (mainly browser, though you can target other environments like Node). Result of such processing is one or more bundles - assembled scripts suitable for targeted environment.
For example, let's say you wrote an ES6 code divided into modules and want be able to run it in browser. If those modules are Node modules, browser won't understand them since they exist only in Node environment. ES6 modules also won't work in older browsers like IE11. Moreover you might have used experimental language features (ES next proposals) that browsers don't implement yet so running such script would just throw errors. Those tools like Webpack and Browserify solve these problems by translating such code to a form browser is able to execute . On top of that, they make it possible to apply a huge variety of optimisations on those bundles.
However, Webpack and Browserify differ in many ways, Webpack offers many tools by default (eg code splitting), while Browserify can do this only after downloading plugins but using both leads to very similar results . It comes down to personal preference (Webpack is trendier). Btw, Webpack is not a task runner, it is just processor of your files (it processes them by so called loaders and plugins) and it can be run (among other ways) by a task runner.
Webpack Dev Server
Webpack Dev Server provides similar solution to Browsersync - a development server where you can deploy your app rapidly as you are working on it, and verify your development progress immediately with the dev server automatically refreshing the browser on code changes or even propagating changed code to browser without reloading with so called hot module replacement.
Task runners vs NPM scripts
I've been using Gulp for its conciseness and easy task writing, but have later found out I need neither Gulp nor Grunt at all. Everything I have ever needed could have been done using NPM scripts to run 3rd-party tools through their API. Choosing between Gulp, Grunt or NPM scripts depends on taste and experience of your team.
While tasks in Gulp or Grunt are easy to read even for people not so familiar with JS, it is yet another tool to require and learn and I personally prefer to narrow my dependencies and make things simple. On the other hand, replacing these tasks with the combination of NPM scripts and (propably JS) scripts which run those 3rd party tools (eg. Node script configuring and running rimraf for cleaning purposes) might be more challenging. But in the majority of cases, those three are equal in terms of results.
Examples
As for the examples, I suggest you have a look at this React starter project, which shows you a nice combination of NPM and JS scripts covering the whole build and deploy process. You can find those NPM scripts in package.json in the root folder, in a property named scripts
. There you will mostly encounter commands like babel-node tools/run start
. Babel-node is a CLI tool (not meant for production use), which at first compiles ES6 file tools/run
(run.js file located in tools) - basically a runner utility. This runner takes a function as an argument and executes it, which in this case is start
- another utility (start.js) responsible for bundling source files (both client and server) and starting the application and development server (the dev server will be probably either Webpack Dev Server or Browsersync).
Speaking more precisely, start.js creates both client and server side bundles, starts express server and after successful start inits Browser-sync, which at the time of writing looked like this (please refer to react starter project for the newest code).
const bs = Browsersync.create();
bs.init({
...(DEBUG ? {} : { notify: false, ui: false }),
proxy: {
target: host,
middleware: [wpMiddleware, ...hotMiddlewares],
},
// no need to watch '*.js' here, webpack will take care of it for us,
// including full page reloads if HMR won't work
files: ['build/content/**/*.*'],
}, resolve)
The important part is proxy.target
, where they set server address they want to proxy, which could be http://localhost:3000, and Browsersync starts a server listening on http://localhost:3001, where the generated assets are served with automatic change detection and hot module replacement. As you can see, there is another configuration property files
with individual files or patterns Browser-sync watches for changes and reloads the browser if some occur, but as the comment says, Webpack takes care of watching js sources by itself with HMR, so they cooperate there.
Now I don't have any equivalent example of such Grunt or Gulp configuration, but with Gulp (and somewhat similarly with Grunt) you would write individual tasks in gulpfile.js like
gulp.task('bundle', function() {
// bundling source files with some gulp plugins like gulp-webpack maybe
});
gulp.task('start', function() {
// starting server and stuff
});
where you would be doing essentially pretty much the same things as in the starter-kit, this time with task runner, which solves some problems for you, but presents its own issues and some difficulties during learning the usage, and as I say, the more dependencies you have, the more can go wrong. And that is the reason I like to get rid of such tools.
I've been also searching for this quite some time since there is a lot of tools out there and each of them benefits us in a different aspect. The community is divided across tools like Browserify, Webpack, jspm, Grunt and Gulp
. You might also hear about Yeoman or Slush
. That's not really a problem, it's just confusing for everyone trying to understand a clear path forward.
Anyway, I would like to contribute something.
1. Package Manager
Package managers simplify installing and updating project dependencies, which are libraries such as: jQuery, Bootstrap
, etc - everything that is used on your site and isn't written by you.
Browsing all the library websites, downloading and unpacking the archives, copying files into the projects — all of this is replaced with a few commands in the terminal.
NPM
stands for: Node JS package manager
helps you to manage all the libraries your software relies on. You would define your needs in a file called package.json
and run npm install
in the command line... then BANG, your packages are downloaded and ready to use. Could be used both for front-end and back-end
libraries.
Bower
: for front-end package management, the concept is same with NPM. All your libraries are stored in a file named bower.json
and then run bower install
in the command line.
The biggest difference between Bower
and NPM
is that NPM does nested dependency tree while Bower requires a flat dependency tree as below.
Quoting from What is the difference between Bower and npm?
NPM
project root
[node_modules] // default directory for dependencies
-> dependency A
-> dependency B
[node_modules]
-> dependency A
-> dependency C
[node_modules]
-> dependency B
[node_modules]
-> dependency A
-> dependency D
Bower
project root
[bower_components] // default directory for dependencies
-> dependency A
-> dependency B // needs A
-> dependency C // needs B and D
-> dependency D
There are some updates on npm 3 Duplication and Deduplication
, please open the doc for more detail.
Yarn
: A new package manager for JavaScript
published by Facebook
recently with some more advantages compared to NPM
. And with Yarn, you still can use both NPM
and Bower
registry to fetch the package. If you've installed a package before, yarn
creates a cached copy which facilitates offline package installs
.
jspm
: is a package manager for the SystemJS
universal module loader, built on top of the dynamic ES6
module loader. It is not an entirely new package manager with its own set of rules, rather it works on top of existing package sources. Out of the box, it works with GitHub
and npm
. As most of the Bower
based packages are based on GitHub
, we can install the those packages using jspm
as well. It has a registry that lists most of the commonly used front-end packages for easier installation.
See the different between Bower
and jspm
: Package Manager: Bower vs jspm
2. Module Loader/Bundling
Most projects of any scale will have their code split between a number of files. You can just include each file with an individual <script>
tag, however, <script>
establishes a new http connection, and for small files – which is a goal of modularity – the time to set up the connection can take significantly longer than transferring the data. While the scripts are downloading, no content can be changed on the page.
Eg
<head>
<title>Wagon</title>
<script src=“build/wagon-bundle.js”></script>
</head>
Eg
<head>
<title>Skateboard</title>
<script src=“connectors/axle.js”></script>
<script src=“frames/board.js”></script>
<!-- skateboard-wheel and ball-bearing both depend on abstract-rolling-thing -->
<script src=“rolling-things/abstract-rolling-thing.js”></script>
<script src=“rolling-things/wheels/skateboard-wheel.js”></script>
<!-- but if skateboard-wheel also depends on ball-bearing -->
<!-- then having this script tag here could cause a problem -->
<script src=“rolling-things/ball-bearing.js”></script>
<!-- connect wheels to axle and axle to frame -->
<script src=“vehicles/skateboard/our-sk8bd-init.js”></script>
</head>
Computers can do that better than you can, and that is why you should use a tool to automatically bundle everything into a single file.
Then we heard about RequireJS
, Browserify
, Webpack
and SystemJS
RequireJS
: is a JavaScript
file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Node
. Eg: myModule.js
// package/lib is a dependency we require
define(["package/lib"], function (lib) {
// behavior for our module
function foo() {
lib.log( "hello world!" );
}
// export (expose) foo to other modules as foobar
return {
foobar: foo
}
});
In main.js
, we can import myModule.js
as dependency and use it.
require(["package/myModule"], function(myModule) {
myModule.foobar();
});
And then in our HTML
, we can refer to use with RequireJS
.
<script src=“app/require.js” data-main=“main.js” ></script>
Read more about CommonJS
and AMD
to get understanding easily. Relation between CommonJS, AMD and RequireJS?
Browserify
: set out to allow use of CommonJS
formatted modules in the browser. Consequently, Browserify
isn't as much a module loader as a module bundler: Browserify
is entirely a build-time tool, producing a bundle of code which can then be loaded client-side. Start with a build machine that has node & npm installed, and get the package:
npm install -g –save-dev browserify
Write your modules in CommonJS
format
//entry-point.js
var foo = require('../foo.js');
console.log(foo(4));
And when happy, issue the command to bundle:
browserify entry-point.js -o bundle-name.js
Browserify recursively finds all dependencies of entry-point and assembles them into a single file:
<script src=”bundle-name.js”></script>
Webpack
: It bundles all of your static assets, including JavaScript
, images, CSS and more, into a single file. It also enables you to process the files through different types of loaders. You could write your JavaScript
with CommonJS
or AMD
modules syntax. It attacks the build problem in a fundamentally more integrated and opinionated manner. In Browserify
you use Gulp/Grunt
and a long list of transforms and plugins to get the job done. Webpack
offers enough power out of the box that you typically don't need Grunt
or Gulp
at all. Basic usage is beyond simple. Install Webpack like Browserify:
npm install -g –save-dev webpack
And pass the command an entry point and an output file:
webpack ./entry-point.js bundle-name.js
SystemJS
: is a module loader that can import modules at run time in any of the popular formats used today ( CommonJS, UMD, AMD, ES6
). It is built on top of the ES6
module loader polyfill and is smart enough to detect the format being used and handle it appropriately. SystemJS
can also transpile ES6 code (with Babel
or Traceur
) or other languages such as TypeScript
and CoffeeScript
using plugins. Want to know what is the node module
and why it is not well adapted to in-browser.
More useful article:
Why jspm
and SystemJS
?
One of the main goals of ES6
modularity is to make it really simple to install and use any Javascript library from anywhere on the Internet ( Github
, npm
, etc.). Only two things are needed:
So with jspm
, you can do it.
jspm install jquery
display.js
var $ = require('jquery');
$('body').append("I've imported jQuery!");
Then you configure these things within System.config({ ... })
before importing your module. Normally when run jspm init
, there will be a file named config.js
for this purpose.
To make these scripts run, we need to load system.js
and config.js
on the HTML page. After that we will load the display.js
file using the SystemJS
module loader.
index.html
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import("scripts/display.js");
</script>
Noted: You can also use npm
with Webpack
as Angular 2 has applied it. Since jspm
was developed to integrate with SystemJS
and it works on top of existing npm
source, so your answer is up to you.
3. Task runner
Task runners and build tools are primarily command-line tools. Why we need to use them: In one word: automation . The less work you have to do when performing repetitive tasks like minification, compilation, unit testing, linting which previously cost us a lot of times to do with command line or even manually.
Grunt
: You can create automation for your development environment to pre-process codes or create build scripts with a config file and it seems very difficult to handle a complex task. Popular in last few years. Every task in Grunt
is an array of different plugin configurations, that simply get executed one after another, in a strictly independent, and sequential fashion.
grunt.initConfig({
clean: {
src: ['build/app.js', 'build/vendor.js']
},
copy: {
files: [{
src: 'build/app.js',
dest: 'build/dist/app.js'
}]
}
concat: {
'build/app.js': ['build/vendors.js', 'build/app.js']
}
// ... other task configurations ...
});
grunt.registerTask('build', ['clean', 'bower', 'browserify', 'concat', 'copy']);
Gulp
: Automation just like Grunt
but instead of configurations, you can write JavaScript
with streams like it's a node application. Prefer these days. This is a Gulp
sample task declaration.
//import the necessary gulp plugins
var gulp = require('gulp');
var sass = require('gulp-sass');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');
//declare the task
gulp.task('sass', function(done) {
gulp.src('./scss/ionic.app.scss')
.pipe(sass())
.pipe(gulp.dest('./www/css/'))
.pipe(minifyCss({
keepSpecialComments: 0
}))
.pipe(rename({ extname: '.min.css' }))
.pipe(gulp.dest('./www/css/'))
.on('end', done);
});
See more: https://medium.com/@preslavrachev/gulp-vs-grunt-why-one-why-the-other-f5d3b398edc4#.fte0nahri
4. Scaffolding tools
Slush and Yeoman
: You can create starter projects with them. For example, you are planning to build a prototype with HTML and SCSS, then instead of manually create some folder like scss, css, img, fonts. You can just install yeoman
and run a simple script. Then everything here for you. Find more here.
npm install -g yo
npm install --global generator-h5bp
yo h5bp
See more: https://www.quora.com/What-are-the-differences-between-NPM-Bower-Grunt-Gulp-Webpack-Browserify-Slush-Yeoman-and-Express
My answer is not really matched with the content of the question but when I'm searching for these knowledge on Google, I always see the question on top so that I decided to answer it in summary as well as why we need to use those tool.
Recently I found a really comprehensive guide from Grab team about how to approach front-end development in 2017. You can check it out as below.
https://github.com/grab/front-end-guide
You can find some technical comparison on npmcompare
Comparing browserify vs. grunt vs. gulp vs. webpack
As you can see webpack is very well maintained with a new version coming out every 4 days on average. But Gulp seems to have the biggest community of them all (with over 20K stars on Github) Grunt seems a bit neglected (compared to the others)
So if need to choose one over the other i would go with Gulp
链接地址: http://www.djcxy.com/p/18056.html上一篇: 在GitHub中合并叉子
下一篇: NPM vs. Bower vs. Browserify vs. Gulp vs. Grunt vs. Webpack