我正在尝试总结我对最流行的 JavaScript 包管理器,捆绑器和任务运行器的了解。如果我错了,请纠正我:
npm & bower是包管理员。他们只是下载依赖项,不知道如何自己构建项目。他们知道什么是调用webpack / gulp / grunt获取所有的依赖后。 bower就像是npm ,但构建了扁平的依赖树(与npm不同,它递归地执行)。含义npm获取每个依赖项的依赖项(可以获取相同的几次),而bower期望您手动包含子依赖项。有时bower和npm分别用于前端和后端(因为每兆字节可能在前端很重要)。 grunt和gulp是任务运行器,可以自动化所有可以自动化的东西(即编译 CSS / Sass,优化图像,制作捆绑并缩小 / 转换它)。 grunt与gulp (就像是maven与gradle或配置与代码)。 Grunt 基于配置单独的独立任务,每个任务打开 / 处理 / 关闭文件。 Gulp 需要的代码量较少,并且基于节点流,这使得它可以构建管道链(无需重新打开同一个文件)并使其更快。 webpack ( webpack-dev-server ) - 对我而言,它是一个热门重新加载更改的任务运行器,可以让你忘记所有 JS / CSS 观察者。 npm / bower + plugins 可以替换任务运行者。他们的能力经常交叉,所以如果你需要在npm + 插件上使用gulp / grunt ,会有不同的含义。但是任务运行者肯定更适合复杂的任务(例如 “在每个构建创建捆绑包,从 ES6 转换到 ES5,在所有浏览器模拟器上运行它,制作屏幕截图并通过 ftp 部署到 dropbox”)。 browserify允许为浏览器打包节点模块。 browserify vs node的require实际上是AMD vs CommonJS 。 问题:
webpack & webpack-dev-server ?官方文档说它是一个模块捆绑器,但对我来说它只是一个任务运行器。 有什么不同? browserify ?对于 node / ES6 导入,我们不能这样做吗? npm + 插件上使用gulp / grunt ? Webpack 和 Browserify 几乎完成相同的工作,即处理您的代码以在目标环境中使用 (主要是浏览器,但您可以针对其他环境,如 Node)。这种处理的结果是一个或多个捆绑 - 适合目标环境的组装脚本。
例如,假设您编写了一个分为模块的 ES6 代码,并希望能够在浏览器中运行它。如果这些模块是节点模块,浏览器将无法理解它们,因为它们仅存在于节点环境中。 ES6 模块也不适用于 IE11 等旧版浏览器。此外,您可能已经使用了浏览器尚未实现的实验语言功能(ES 下一个提议),因此运行此类脚本只会引发错误。像 Webpack 和 Browserify 这样的工具通过将这些代码转换为能够执行的表单浏览器来解决这些问题。最重要的是,它们可以对这些捆绑包应用各种各样的优化。
但是,Webpack 和 Browserify 在许多方面有所不同,默认情况下 Webpack 提供了许多工具(例如代码拆分),而 Browserify 只能在下载插件后才能执行此操作,但使用这两种工具会产生非常相似的结果 。归结为个人偏好(Webpack 更具时尚性)。顺便说一下,Webpack 不是一个任务运行器,它只是文件的处理器(它通过所谓的加载器和插件处理它们),它可以由任务运行器运行(以及其他方式)。
Webpack Dev Server 为 Browsersync 提供了类似的解决方案 - 一个开发服务器,您可以在其中快速部署应用程序,并立即验证开发进度,开发服务器会自动刷新代码更改浏览器,甚至将更改后的代码传播到浏览器无需重新加载所谓的热模块更换。
我一直在使用 Gulp 的简洁和简单的任务写作,但后来发现我根本不需要 Gulp 和 Grunt。我所需要的一切都可以使用 NPM 脚本通过其 API 运行第三方工具。 在 Gulp,Grunt 或 NPM 脚本之间进行选择取决于团队的品味和经验。
虽然 Gulp 或 Grunt 中的任务很容易阅读,即使对于不太熟悉 JS 的人来说,它也是另一种需要和学习的工具,我个人更喜欢缩小我的依赖关系并使事情变得简单。另一方面,使用 NPM 脚本和(可运行的 JS)脚本组合替换这些任务,这些脚本运行这些第三方工具(例如,节点脚本配置和运行rimraf以进行清理)可能更具挑战性。但在大多数情况下, 这三者在结果方面是平等的。
至于这些例子,我建议你看看这个React 启动项目 ,它展示了一个包含整个构建和部署过程的 NPM 和 JS 脚本的完美组合。您可以在根文件夹中的 package.json 中找到名为scripts的属性中的 NPM scripts 。那里你将遇到像babel-node tools/run start这样的命令。 Babel-node 是一个 CLI 工具(不适合生产使用),它首先编译 ES6 文件tools/run (位于工具中的 run.js 文件) - 基本上是一个运行器实用程序。这个运行器将一个函数作为参数并执行它,在这种情况下是start - 另一个实用程序(start.js)负责捆绑源文件(客户端和服务器)并启动应用程序和开发服务器(开发服务器将是可能是 Webpack Dev Server 或 Browsersync)。
更确切地说,start.js 创建客户端和服务器端捆绑包,启动快速服务器并在成功启动后进入浏览器同步,在编写本文时看起来像这样(请参阅反应启动项目以获取最新代码)。
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 ,其中生成的资产被提供具有自动变化检测和热模块更换功能。正如您所看到的,还有另一个配置属性files包含单个文件或模式浏览器同步监视更改并重新加载浏览器(如果有的话),但正如评论所说,Webpack 负责用 HMR 自己观看 js 源,所以他们在那里合作。
现在我没有任何 Grunt 或 Gulp 配置的等效示例,但是使用 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
});你在哪里做的几乎与使用入门套件完全相同,这次是使用任务运行器,它为你解决了一些问题,但在学习使用过程中提出了自己的问题和一些困难,正如我所说,你拥有的依赖性越多,就越容易出错。这就是我想摆脱这些工具的原因。
2018 年 6 月更新
如果你从一开始就不去那里学习现代 JavaScript 很难。如果您是新来者,请记得查看这篇优秀的文章,以便更好地了解。
https://medium.com/the-node-js-collection/modern-javascript-explained-for-dinosaurs-f695e9747b70
2017 年 7 月更新
最近,我从 Grab 团队找到了一份关于如何在 2017 年进行前端开发的非常全面的指南。您可以查看如下。
https://github.com/grab/front-end-guide
我一直在寻找这个,因为那里有很多工具,每个工具都有不同的方面让我们受益。社区分为Browserify, Webpack, jspm, Grunt and Gulp 。你可能也听说过Yeoman or Slush 。这不是一个真正的问题,对于每个试图理解明确前进道路的人来说,这只会令人困惑。
无论如何,我想贡献一些东西。
1. 包管理器
软件包管理器简化了项目依赖项的安装和更新,这些库是如下的库: jQuery, Bootstrap等 - 您网站上使用的所有内容都不是由您编写的。
浏览所有图书馆网站,下载和解压缩档案,将文件复制到项目中 - 所有这些都被终端中的一些命令所取代。
NPM代表: Node JS package manager可以帮助您管理软件所依赖的所有库。您可以在名为package.json的文件中定义您的需求,并在命令行中运行npm install ... 然后 BANG,您的软件包已下载并可供使用。可用于front-end and back-end库。
Bower :对于前端包管理,这个概念与 NPM 相同。所有库都存储在名为bower.json的文件中,然后在命令行中运行bower install 。
Bower和NPM之间的最大区别在于 NPM 执行嵌套依赖树,而 Bower 需要平面依赖树,如下所示。
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 Dproject 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新包管理器,与NPM相比具有更多优势。使用 Yarn,您仍然可以使用NPM和Bower注册表来获取包。如果您之前已安装过软件包,则yarn会创建一个缓存副本,以便于offline package installs 。
jspm :是SystemJS通用模块加载器的包管理器,构建于动态ES6模块加载器之上。它不是一个全新的包管理器,它有自己的一套规则,而是在现有的包源之上工作。开箱即用,它适用于GitHub和npm 。由于大多数基于Bower的软件包都基于GitHub ,我们也可以使用jspm安装这些软件包。它有一个注册表,列出了大多数常用的前端软件包,以便于安装。
查看
Bower和jspm之间的不同: Package Manager:Bower vs jspm
2. 模块加载器 / 捆绑
任何规模的大多数项目都将在许多文件之间分配代码。您可以使用单个<script>标记包含每个文件,但是, <script>建立新的 http 连接,对于小文件 - 这是模块化的目标 - 设置连接的时间可能比传输时间长得多数据。在下载脚本时,页面上不能更改任何内容。
例如
<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完全是一个构建时工具,产生一组代码,然后可以在客户端加载。 从安装了 node&npm 的构建计算机开始,获取包:
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.jsBrowserify 以递归方式查找入口点的所有依赖项,并将它们组合到一个文件中:
<script src=”bundle-name.js”></script>Webpack :它将所有静态资产(包括JavaScript ,图像,CSS 等)捆绑到一个文件中。它还使您能够通过不同类型的加载器处理文件。您可以使用CommonJS或AMD模块语法编写JavaScript 。它以一种从根本上更加整合和自以为是的方式攻击构建问题。在Browserify您可以使用Gulp/Grunt以及一长串变换和插件来完成工作。 Webpack提供了足够的电源,您通常根本不需要Grunt或Gulp 。 基本用法非常简单。像 Browserify 一样安装 Webpack:
npm install -g –save-dev webpack并将命令传递给入口点和输出文件:
webpack ./entry-point.js bundle-name.jsSystemJS :是一个模块加载器, 可以在运行时以任何当前使用的流行格式 ( CommonJS, UMD, AMD, ES6 ) 导入模块 。它建立在ES6模块加载器 polyfill 之上,并且足够智能,可以检测正在使用的格式并对其进行适当处理。 SystemJS还可以使用插件转换 ES6 代码(使用Babel或Traceur )或其他语言,如TypeScript和CoffeeScript 。 想知道什么是
node module以及为什么它不能很好地适应浏览器。更有用的文章:
为什么选择
jspm和SystemJS?
ES6模块化的主要目标之一是使安装和使用互联网上任何地方的任何 Javascript 库非常简单(Github,npm等)。只需要两件事:
- 用于安装库的单个命令
- 一行代码导入库并使用它
所以使用
jspm,你可以做到。
- 使用以下命令安装库:
jspm install jquery- 使用单行代码导入库,无需在 HTML 文件内部进行外部引用。
display.js
var $ = require('jquery'); $('body').append("I've imported jQuery!");
然后在导入模块之前在
System.config({ ... })配置这些内容。通常在运行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 应用它时,你也可以使用
npm和Webpack。由于jspm是为了与SystemJS集成而SystemJS,它可以在现有的npm源之上npm,因此您的答案取决于您。
3. 任务运行员
任务运行器和构建工具主要是命令行工具。为什么我们需要使用它们:一句话: 自动化 。在执行重复性任务(例如缩小,编译,单元测试,linting)时 ,您需要做的工作越少,以前需要花费很多时间才能完成命令行甚至手动操作。
Grunt :您可以为开发环境创建自动化,以预处理代码或使用配置文件创建构建脚本,并且处理复杂任务似乎非常困难。在过去几年流行。 Grunt中的每个任务都是一系列不同的插件配置,只需一个接一个地以严格独立和顺序的方式执行。
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一样,但是你可以用流编写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 :你可以用它们创建入门项目。例如,您计划使用 HTML 和 SCSS 构建原型,然后手动创建一些文件夹,如 scss,css,img,fonts。你可以安装自己的yeoman并运行一个简单的脚本。那么一切都在这里给你。 在这里找到更多。
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
我的回答与问题的内容并不完全匹配,但当我在谷歌上搜索这些知识时,我总是在顶部看到这个问题,所以我决定总结一下。希望你们发现它有用。
你可以在npmcompare上找到一些技术比较
比较 browserify 与 grunt 与 gulp 对比 webpack
正如您所看到的,webpack 得到了很好的维护,平均每 4 天推出一个新版本。但 Gulp 似乎拥有最大的社区(在 Github 上有超过 20K 的明星)Grunt 似乎有点被忽视(与其他人相比)
因此,如果需要选择一个而不是另一个,我会选择 Gulp