NPM与Bower vs. Browserify vs. Gulp vs. Grunt vs. Webpack
我试图总结一下最stream行的JavaScript包pipe理器,打包器和任务运行器的知识。 请纠正我,如果我错了:
-
npm
&bower
是包pipe理者。 他们只是下载依赖关系,不知道如何自己构build项目。 他们知道的是在获取所有依赖关系之后调用webpack
/webpack
/grunt
。 -
bower
就像npm
,但build立平坦的依赖树(不像recursion的npm
)。 这意味着npm
为每个依赖获取依赖关系(可能会获取相同的几次),而bower
期望您手动包含子依赖关系。 有时,bower
和npm
分别用于前端和后端(因为每兆字节可能在前端)。 -
grunt
和gulp
是任务运行器,可以自动执行所有可以自动化的任务(例如,编译CSS / Sass,优化映像,制作包并缩小/转储它)。 -
grunt
与gradle
(就像maven
与gradle
或者configuration与代码一样)。 Grunt基于configuration单独的独立任务,每个任务打开/处理/closures文件。 Gulp需要的代码量较less,基于Nodestream,这使得它可以构buildpipe道链(不重新打开相同的文件)并使其更快。 -
webpack
(webpack-dev-server
) – 对我来说,这是一个任务运行的热点重新加载的变化,让你忘记所有的JS / CSS的观察员。 -
npm
/bower
+插件可能取代任务跑步者。 他们的能力经常相交,所以如果你需要在npm
+插件上使用gulp
/grunt
,会有不同的含义。 但是对于复杂任务来说,任务运行者肯定更好(例如,“在每个构build中创build包,从ES6到ES5的转储,在所有浏览器模拟器上运行,通过ftp进行截图并部署到保pipe箱”)。 -
browserify
允许为浏览器打包节点模块。browserify
vsnode
的require
实际上是AMD与CommonJS 。
问题:
- 什么是
webpack
&webpack-dev-server
? 官方文档说这是一个模块打包器,但对我来说,这只是一个任务跑步者。 有什么不同? - 你会在哪里使用
browserify
? 我们不能做同样的节点/ ES6import? - 你什么时候用
npm
+插件使用gulp
/grunt
? - 请提供您需要使用组合的例子
Webpack和Browserify几乎完成了同样的工作,它将你的模块绑定到一个浏览器环境中(尽pipe你可以将其他环境作为目标,比如绑定你的服务器端ES6的Node代码)。 例如Node模块是浏览器中不存在的一个特性,ES6模块在任何浏览器中都没有实现,这就是为什么需要捆绑的东西。 然而,它们在很多方面有所不同,Webpack默认提供了很多工具(例如代码分割),而Browserify只能在下载插件后才能做到这一点,但是使用这两种方法的结果非常相似。 这归结为个人喜好(我习惯了Webpack)。 Webpack不是任务运行者,它只是你的文件的处理器(它通过所谓的加载器来处理它们)直接从CLI或任务运行器运行。
webpack-dev-server
提供了一些类似于Browsersync的服务器,在这里你可以部署你的应用程序,并通过dev-server立即validation你的FE开发进度,自动刷新浏览器,甚至在没有热部署的情况下传播更改(例如React组件)。
我一直在使用Gulp的简洁和简单的任务写作,但后来发现我根本不需要Gulp和Grunt。 我所需要的一切都可以通过使用npm脚本通过API运行第三方工具来完成。 在Gulp,Grunt或npm脚本之间进行select取决于您的口味,JS与您合作的开发人员的经验和经验。
虽然Gulp(或Grunt也许)中的任务很容易阅读,即使对JS不太熟悉的人也是如此,它是另一个需要和学习的工具,我个人更喜欢缩小我的依赖关系,使事情变得简单。 另一方面,用npm脚本和运行文件(如Webpack这样的工具的configuration和执行function所在)来replace这些任务更具挑战性。 但在大多数情况下,这三者在结果上是相同的。
至于示例,我build议你看看这个React初学者项目 ,它展示了npm脚本,Webpack和Browsersync的完美结合。 您可以在根文件夹中的package.json中find名为scripts
的属性中的那些npm scripts
。 在那里你将会遇到像babel-node tools/run start
这样的命令。 Babel-node是一个CLI工具(不用于生产使用),它首先编译ES6文件tools/run
(run.js文件位于工具中 ) – 基本上是一个runner工具。 这个跑步者将一个函数作为参数运行,在这种情况下,它是start
– 另一个负责捆绑源文件(客户端和服务器)的实用程序(start.js),启动node-express服务器,然后是Browsersync,一个将开发变化传播给浏览器的代理。
更确切地说,start.js导入客户端的Webpackconfiguration文件,操作它来添加热模块replacefunction,然后创build客户端和服务器端包,通过另一个名为runServer.js的实用程序启动节点服务器,并在Browsersync中成功启动后看起来像这样
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)
最重要的部分是proxy.target
,您可以在其中设置要代理的服务器地址,可以是http:// localhost:3000 ,Browsersync将启动监听http:// localhost:3001的服务器,其中部署了相同的应用程序,但随着热模块更换,所以你可以体验到源文件更改传播到浏览器立即甚至没有重新加载。 正如你所看到的,有另一个configuration属性files
与个人文件或模式Browsersync手表更改和重新加载浏览器,如果发生,但正如评论所说,Webpack照顾自己与HMR的js来源,所以他们在那里合作。
现在我没有任何这样的Grunt或Gulpconfiguration的等价例子,但是使用Gulp(和Grunt有些相似),你可以在gulpfile.js中编写单独的任务
gulp.task('bundle', function() { // bundling source files with some gulp plugins like gulp-webpack maybe }); gulp.task('start', function() { // starting server and stuff });
在那里你会做基本上相同的事情,在入门套件,这一次与任务运行,这解决了一些问题给你,但提出了自己的问题和在学习使用过程中的一些困难,正如我所说的你有更多的依赖关系,更可能出错。 这就是我喜欢摆脱这种工具的原因。
我也一直在寻找这个相当长的一段时间,因为有很多的工具,每个都在不同的方面给我们带来好处。 这个社区被分成了诸如Browserify, Webpack, jspm, Grunt and Gulp
。 你也可能会听说Yeoman or Slush
。 这不是一个真正的问题,只是让每个人都试图理解一条明确的道路而感到困惑。
无论如何,我想贡献一些东西。
1.软件包pipe理器
程序包pipe理器简化了安装和更新项目依赖关系,这些依赖项是库,如: jQuery, Bootstrap
等 – 在您的网站上使用并且不是由您编写的所有东西。
浏览所有的图书馆网站,下载和解压档案,复制文件到项目中 – 所有这些都被terminal中的一些命令所取代。
-
NPM
代表:Node JS package manager
可以帮助您pipe理您的软件依赖的所有库。 您可以在一个名为package.json
的文件中定义您的需求,然后在命令行中运行npm install
…然后BANG,您的软件包将被下载并准备使用。 可以用于front-end and back-end
库。 -
Bower
:对于前端包pipe理,这个概念和NPM是一样的。 所有库都存储在名为bower.json
的文件中,然后在命令行中运行bower install
。
Bower
和NPM
最大的区别是NPM嵌套了依赖树,而Bower需要一个平坦的依赖树。引用Bower和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
鲍尔
project root [bower_components] // default directory for dependencies -> dependency A -> dependency B // needs A -> dependency C // needs B and D -> dependency D
npm 3 Duplication and Deduplication
有一些更新,请打开文档以获取更多详细信息。
-
Yarn
:最近Facebook
发布的一个新的JavaScript
包pipe理器,与NPM
相比,有更多的优势。 使用Yarn,您仍可以使用NPM
和Bower
registry来获取软件包。 如果您之前已经安装了一个软件包,yarn
会创build一个caching副本,以便于offline package installs
。 -
jspm
:是SystemJS
通用模块加载器的包pipe理器,构build在dynamicES6
模块加载器之上。 它并不是一个全新的包pipe理器,它有自己的一套规则,而是在现有的包源头上运行。 开箱即用,它适用于GitHub
和npm
。 由于大部分基于Bower
的软件包都基于GitHub
,我们也可以使用jspm
来安装这些软件包。 它有一个registry,列出了大多数常用的前端软件包,以便于安装。
看看
Bower
和jspm
之间的不同: 包pipe理器:鲍尔vs jspm
2.模块加载器/捆绑
大多数任何规模的项目都将他们的代码分割成多个文件。 您可以使用单独的<script>
标签包含每个文件,但是<script>
build立一个新的http连接,对于小文件这是一个模块化目标,build立连接的时间可能比传输数据。 在下载脚本的同时,页面上不能更改内容。
- 下载时间的问题很大程度上可以通过将一组简单的模块连接成单个文件并将其缩小来解决。
例如
<head> <title>Wagon</title> <script src=“build/wagon-bundle.js”></script> </head>
- 性能是以牺牲灵活性为代价的。 如果你的模块具有相互依赖性,这种缺乏灵活性可能是一个不争的事实。
例如
<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>
计算机可以做的比你更好,这就是为什么你应该使用一个工具来自动捆绑一切到一个单一的文件。
然后我们听说了RequireJS
, Browserify
, Webpack
和SystemJS
-
RequireJS
:是一个JavaScript
文件和模块加载器。 它针对浏览器内的使用进行了优化,但可以在其他JavaScript环境中使用,如Node
。
例如: 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 } });
在main.js
,我们可以导入myModule.js
作为依赖项并使用它。
require(["package/myModule"], function(myModule) { myModule.foobar(); });
然后在我们的HTML
,我们可以参考使用RequireJS
。
<script src=“app/require.js” data-main=“main.js” ></script>
阅读关于
CommonJS
和AMD
更多信息,以便于理解。 CommonJS,AMD和RequireJS的关系?
-
Browserify
:允许在浏览器中使用CommonJS
格式的模块。 因此,Browserify
不像模块Browserify
程序那样是一个模块加载程序:Browserify
完全是一个构build时间工具,生成一个可以在客户端加载的代码包。
从安装了node&npm的构build机器开始,获取包:
npm install -g –save-dev browserify
用CommonJS
格式编写你的模块
//entry-point.js var foo = require('../foo.js'); console.log(foo(4));
而当高兴时,发出命令捆绑:
browserify entry-point.js -o bundle-name.js
Browserifyrecursion地查找入口点的所有依赖关系,并将它们组装到一个文件中:
<script src=”bundle-name.js”></script>
-
Webpack
:将所有静态资源(包括JavaScript
,图像,CSS等)捆绑到一个文件中。 它还使您能够通过不同types的加载程序来处理文件。 你可以用CommonJS
或AMD
模块语法来编写你的JavaScript
。 它从根本上更加综合和自信地攻击build造问题。 在Browserify
您可以使用Gulp/Grunt
和一长串转换和插件来完成工作。Webpack
提供了足够的function,你通常不需要Grunt
或Gulp
。
基本的用法是非常简单的。 像Browserify一样安装Webpack:
npm install -g –save-dev webpack
并通过命令一个入口点和一个输出文件:
webpack ./entry-point.js bundle-name.js
-
SystemJS
:是一个模块加载器, 可以在运行时导入当今使用的任何常用格式 (CommonJS, UMD, AMD, ES6
)。 它build立在ES6
模块加载器polyfill之上,足够聪明地检测正在使用的格式并适当地处理它。SystemJS
还可以使用插件来传输ES6代码(使用Babel
或Traceur
)或其他语言,如TypeScript
和CoffeeScript
。
想知道什么是
node module
,为什么它不适合在浏览器中。更有用的文章:
为什么
jspm
和SystemJS
?
ES6
模块化的主要目标之一就是使得从互联网上的任何地方(Github
,npm
等)安装和使用任何Javascript库变得非常简单。 只需要两件事情:
- 一个命令来安装库
- 一行代码来导入库并使用它
所以用
jspm
,你可以做到。
- 用命令安装库:
jspm install jquery
- 用一行代码导入库,不需要在你的HTML文件里面进行外部引用。
display.js
var $ = require('jquery'); $('body').append("I've imported jQuery!");
然后在导入你的模块之前在
System.config({ ... })
configuration这些东西。 通常当运行jspm init
,会有一个名为config.js
的文件用于此目的。为了使这些脚本运行,我们需要在HTML页面上加载
system.js
和config.js
。 之后,我们将使用SystemJS
模块加载器加载display.js
文件。的index.html
<script src="jspm_packages/system.js"></script> <script src="config.js"></script> <script> System.import("scripts/display.js"); </script>
注意:Angular 2已经应用了,你也可以在
Webpack
使用npm
。 由于jspm
是为了与SystemJS
集成而SystemJS
,它在现有的npm
源代码上工作,所以你的答案取决于你。
3.任务运动员
任务运行者和构build工具主要是命令行工具。 为什么我们需要使用它们:一句话就是: 自动化 。 在执行重复性任务(如缩小,编译,unit testing,linting)时需要做的工作量较less,而这些工作之前花费了大量的时间来处理命令行,甚至手动完成。
-
Grunt
:您可以为您的开发环境创build自动化以预先处理代码或使用configuration文件创build构build脚本,处理复杂的任务似乎非常困难。 在过去几年stream行。
Grunt
中的每个任务都是一组不同的插件configuration,它们以一种严格独立的顺序方式一个接一个地执行。
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
:自动化就像Grunt
一样,但不是configuration,你可以用stream来编写JavaScript
,就像它是一个节点应用程序一样。 喜欢这些天。
这是一个Gulp
示例任务声明。
//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); });
查看更多: https : //medium.com/@preslavrachev/gulp-vs-grunt-why-one-why-the-other-f5d3b398edc4#.fte0nahri
4.脚手架工具
-
Slush and Yeoman
:您可以使用它们创build初学者项目。 例如,您打算使用HTML和SCSS构build原型,而不是手动创build一些文件夹,如scss,css,img,fonts。 你可以安装yeoman
并运行一个简单的脚本。 那么一切为了你。
在这里find更多。
npm install -g yo npm install --global generator-h5bp yo h5bp
查看更多: https : //www.quora.com/What-are-the-differences-between-NPM-Bower-Grunt-Gulp-Webpack-Browserify-Slush-Yeoman-and-Express
我的答案与问题的内容并不完全一致,但是当我在Google上search这些知识时,我总是看到这个问题,所以我决定总结这个问题,以及为什么我们需要使用这些工具。
最近我从Grab团队那里find了一个非常全面的指南,介绍如何在2017年实现前端开发。您可以查看下面的内容。
你可以在npmcompare上find一些技术比较
比较browserify与grunt与gulp与webpack
正如你可以看到,webpack平均每4天出现一个新版本,维护得非常好。 但是Gulp似乎拥有最大的社区(Github上有超过20K星)Grunt似乎有点被忽略(与其他人相比)
所以,如果需要select一个,我会与Gulp一起去
关于npm:npm3的一个小logging尝试以平坦的方式安装依赖关系
https://docs.npmjs.com/how-npm-works/npm3#npm-v3-dependency-resolution
好,他们都有一些相似之处,他们以不同的方式为你做同样的事情,我把他们分成三大类,分别是:
1)模块捆绑器
webpack和browserify作为stream行的,像任务运行者一样工作,但更灵活,如同它将所有的东西捆绑在一起作为你的设置,所以你可以指向bundle.js的结果,例如在一个单一的文件,包括CSS和Javascript,每个细节更多,请看下面的细节:
的WebPack
webpack是现代JavaScript应用程序的模块打包程序。 当webpack处理你的应用程序时,它recursion地build立一个依赖图,包括你的应用程序需要的每个模块,然后把所有这些模块打包成less量的包,通常只有一个包被浏览器加载。
这是令人难以置信的可configuration,但要开始您只需要了解四个核心概念:入口,输出,加载器和插件。
本文档旨在对这些概念进行高级概述,同时提供指向具体概念特定用例的链接。
这里更多
browserify
Browserify是一个开发工具,它允许我们编写node.js风格的模块,以便在浏览器中使用。 就像节点一样,我们将模块写入单独的文件,使用module.exports和exportsvariables导出外部方法和属性。 我们甚至可以要求使用require函数的其他模块,如果我们省略了相对path,它将parsing到node_modules目录中的模块。
这里更多
2)任务跑步者
gulp和grunt是任务运行者,基本上他们是做什么的,创build任务并在任何时候运行它们,例如你安装一个插件来缩小你的CSS,然后每次运行它来缩小,更详细的每个细节:
吞
gulp.js是Fractal Innovations的开源JavaScript工具包,也是GitHub的开源社区,在前端Web开发中用作stream式构build系统。 它是一个build立在Node.js和Node Package Manager(npm)上的任务运行器,用于Web开发中涉及的耗时和重复性任务的自动化,如缩小,串联,caching清除,unit testing,linting,优化等。一个代码configuration的方法来定义它的任务,并依靠它的小型单一目的的插件来执行它们。 gulp生态系统有1000多个这样的插件可供select。
这里更多
咕噜
Grunt是一个JavaScript任务运行器,一种用于自动执行常用任务(如缩小,编译,unit testing,linting等)的工具。它使用命令行界面来运行定义在文件中的自定义任务(称为Gruntfile) 。 Grunt由Ben Alman创build,用Node.js编写。 它通过npm分发。 目前,Grunt生态系统中有五千多个插件。
这里更多
3)包装经理
软件包pipe理器,他们所做的就是在你的应用程序中pipe理你所需要的插件,并通过github等使用package.json来安装它们,非常方便地更新你的模块,安装它们并共享你的应用程序,更多细节:
NPM
npm是JavaScript编程语言的包pipe理器。 它是JavaScript运行时环境Node.js的默认包pipe理器。 它由命令行客户端(也称为npm)和一个名为npmregistry的公共包的在线数据库组成。 通过客户端访问registry,可以通过npm网站浏览和search可用的软件包。
这里更多
亭子
Bower可以pipe理包含HTML,CSS,JavaScript,字体甚至图像文件的组件。 Bower不会连接或缩小代码或做其他任何事情 – 它只是安装所需的软件包的正确版本及其依赖关系。 为了开始,鲍尔的工作是从各处获取和安装软件包,照顾狩猎,寻找,下载和保存你正在寻找的东西。 Bower在清单文件bower.json中跟踪这些包。
这里更多
以及最新的软件包pipe理器,不应该错过,在实际的工作环境中,与我之前大多数人使用的npm相比,它们年轻而快速,对于重新安装模块,它会双重检查node_modules文件夹以检查模块的存在,也似乎安装模块需要更less的时间:
纱
纱是你的代码的包pipe理器。 它允许您使用和分享来自世界各地的其他开发人员的代码。 纱线能够快速,安全,可靠地完成工作,所以您不必担心。
Yarn允许您使用其他开发人员针对不同问题的解决scheme,使您可以更轻松地开发您的软件。 如果您遇到问题,您可以报告问题或回馈,问题解决后,您可以使用纱线保持最新状态。
代码是通过称为包(有时称为模块)的东西共享的。 一个包包含了所有被共享的代码以及一个描述包的package.json文件。
这里更多
什么是webpack&webpack-dev-server? 官方文档说这是一个模块打包器,但对我来说,这只是一个任务跑步者。 有什么不同?
webpack-dev-server是一个实时重载Web服务器, Webpack开发人员可以使用它来获得即时反馈。 它只能在开发过程中使用。
这个项目深受nof5unit testing工具的启发。
Webpack顾名思义将为Web创build一个单一的 包装时代。 该软件包将被最小化,并合并成一个文件(我们仍然生活在HTTP 1.1时代)。 Webpack实现了将资源(JavaScript,CSS,图像)组合起来并像下面这样注入的魔力: <script src="assets/bundle.js"></script>
。
它也可以称为模块打包器,因为它必须理解模块依赖关系,以及如何获取依赖关系并将它们捆绑在一起。
你会在哪里使用browserify? 我们不能做同样的节点/ ES6import?
您可以在使用Webpack的相同任务上使用Browserify 。 但是Webpack更加紧凑。
请注意, Webpack2中的ES6模块加载器function正在使用System.import ,而不是一个本机支持的浏览器。
你什么时候用npm +插件使用gulp / grunt?
你可以忘记 吞咽,咕噜,Brokoli,早午餐和鲍尔 。 直接使用npm命令行脚本,你可以在这里为Gulp消除这些额外的包:
var gulp = require('gulp'), minifyCSS = require('gulp-minify-css'), sass = require('gulp-sass'), browserify = require('gulp-browserify'), uglify = require('gulp-uglify'), rename = require('gulp-rename'), jshint = require('gulp-jshint'), jshintStyle = require('jshint-stylish'), replace = require('gulp-replace'), notify = require('gulp-notify'),
在为项目创buildconfiguration文件时,可以使用Gulp和Gruntconfiguration文件生成器。 这样你就不需要安装Yeoman或类似的工具。
纱是最近的包pipe理器,可能值得提及。 那么,在那里: https : //yarnpkg.com/
Afaik,它可以获取npm和bower的依赖关系,并有其他赞赏的function。
StackShare一次提供三个工具的并排(或叠加 )。
这里是npm与鲍尔vs. Browserify和吞噬与Webpack与Grunt
在这些比较页面上,您可以find以下内容:
- 每个从StackShare社区收到的票数
- 哪些公司在他们的技术堆栈中使用它们
- 每个时间的兴趣水平
- 每个工具的优点
Webpack
是一个捆绑软件。 像Browserfy
一样,它在模块请求( require
或import
)的代码库中查找并recursionparsing它们。 更重要的是,你可以configurationWebpack
来解决不仅仅是类似JavaScript的模块,而是CSS,图像,HTML,从字面上来看,都是一切。 什么特别让我对Webpack
兴奋,你可以在同一个应用程序中结合编译和dynamic加载的模块。 因此可以获得真正的性能提升,特别是在HTTP / 1.x上。 你如何做到这一点我在这里描述的例子http://dsheiko.com/weblog/state-of-javascript-modules-2017/作为一个替代的捆绑人可以想到;Rollup.js
( https:// rollupjs。 org / ),它在编译过程中优化了代码,但剥离了所有find的未使用的块。
对于AMD
,而不是RequireJS
可以使用本地ES2016 module system
,但加载了System.js
( https://github.com/systemjs/systemjs )
此外,我想指出, npm
经常被用作grunt
或gulp
的自动化工具。 查看https://docs.npmjs.com/misc/scripts 。 我个人现在去npm脚本只是避免其他自动化工具,虽然在过去我非常grunt
。 与其他工具,你必须依靠无数的插件包,往往是不好写,没有积极维护。 npm
知道它的包,所以你打电话给任何本地安装的软件包名称如:
{ "scripts": { "start": "npm http-server" }, "devDependencies": { "http-server": "^0.10.0" } }
其实你一般不需要任何插件,如果软件包支持CLI的话。