>  기사  >  웹 프론트엔드  >  jQuery_jquery를 사용한 Browserify 프로그래밍에 대한 슈퍼 가이드

jQuery_jquery를 사용한 Browserify 프로그래밍에 대한 슈퍼 가이드

WBOY
WBOY원래의
2016-05-16 15:48:371471검색

소개
1. 수동으로

과거에는 새로운 웹 프로젝트를 시작한 후 jQuery를 사용하려고 생각했습니다. 브라우저를 열고 jQuery 공식 웹사이트를 찾아 눈길을 끄는 "jQuery 다운로드" 버튼을 클릭하여 다운로드했습니다. .js 파일을 만든 다음 프로젝트 디렉터리에 놓습니다. 사용해야 하는 곳에서는 3f1c4e4b6b16bbbd69b2ee476dc4f83a를 사용하여 다음과 같이 소개하세요.

<script src="path/to/jquery.js"></script>

2. 바우어

나중에 Bower와 같은 패키지 관리 도구를 사용하기 시작했습니다. 따라서 프로세스는 다음과 같습니다. 먼저 명령줄을 열고 Bower를 사용하여 jQuery를 설치합니다.

bower install jquery

계속해서 3f1c4e4b6b16bbbd69b2ee476dc4f83a를 사용해 보세요.

<script src="bower_components/jquery/dist/jquery.js"></script>

3. npm&브라우저파이

이제 다음과 같은 새로운 선택이 생겼습니다.

npm을 사용하여 명령줄에서 jQuery를 설치하세요.

npm install jquery

이를 사용해야 하는 JavaScript 코드에서는 다음과 같이 도입하세요.

var $ = require("jquery");

예, 이것이 npm 패키지를 사용하는 일반적인 방법입니다. 하지만 특별한 점은 이 npm 패키지가 잘 알려진 jquery이며 브라우저에서 사용된다는 것입니다.

Browserify는 이름에서 알 수 있듯이 원래 서버 측에 속한 Node와 npm을 브라우저 측에서 사용할 수 있도록 해줍니다.

분명히 위 과정은 아직 끝나지 않았으며, 다음 단계는 Browserify 작업입니다(위 코드가 위치한 파일이 main.js라고 가정):

browserify main.js -o bundle.js

마지막으로 3f1c4e4b6b16bbbd69b2ee476dc4f83a를 사용하여 Browserify에서 생성된 Bundle.js 파일을 참조하세요.

<script src="bundle.js"></script>

Browserify에 구축된 세 번째 옵션입니다.

잠깐, 왜 이전보다 더 복잡해졌나요?
CommonJS 스타일 모듈 및 종속성 관리

사실 require()는 이 겉보기에 더 복잡해 보이는 프로세스에서 특별한 의미를 갖습니다.

Browserify는 단순히 JavaScript 패키지를 쉽게 참조할 수 있게 해주는 도구가 아닙니다. 주요 기능은 JavaScript 모듈과 종속성 관리입니다. (선생님의 본업입니다)

모듈 및 종속성 관리에 관한 한 이미 RequireJS, 국내 Sea.js 등 우수한 작품이 있습니다. 이제 Browserify는 우리에게 새로운 선택권을 주었습니다.
Browserify는 Node의 모듈 시스템을 참조하며 require()를 사용하여 다른 모듈을 도입하고 module.exports를 사용하여 모듈을 내보내는 데 동의합니다. 제 생각에는 Browserify는 "런타임" 모듈 로더 제공에 중점을 두지 않고 사전 컴파일을 강조한다는 점에서 RequireJS 및 Sea.js와 다릅니다. 사전 컴파일에는 추가 프로세스가 필요하지만 이에 따라 더 이상 패키징 레이어를 추가하기 위해 특정 규칙을 따를 필요가 없습니다. 따라서 이에 비해 Browserify에서 제공하는 구성 방법은 CommonJS 사양과 더 간결하고 일관성이 있습니다.

Node를 작성하는 것처럼 JavaScript를 구성하면 Browserify가 브라우저에서 정상적으로 실행되도록 합니다.
설치 및 사용
명령줄 형식

명령줄 형식이 가장 단순해 보이기 때문에 공식적인 사용법입니다.

Browserify 자체도 npm을 통해 설치되는 npm입니다.

npm install -g browserify

여기서 -g 매개변수는 전역을 나타내므로 명령줄에서 직접 사용할 수 있습니다. 그런 다음 .js 파일(예: Entry.js)에 browserify 명령을 실행합니다.

browserify entry.js -o bundle.js

Browserify는 코드의 require()를 재귀적으로 분석한 다음 컴파일된 파일(여기서는bundle.js)을 생성합니다. 컴파일된 파일 내에서 모든 JavaScript 모듈이 함께 병합되고 종속성이 설정되었습니다. 마지막으로 이 컴파일된 파일을 html로 인용합니다(소개 부분과 동일합니다).

<script src="bundle.js"></script>

이 컴파일 명령의 구성 매개변수는 node-browserify#usage를 참조하세요. 보다 세부적인 구성을 하고 싶다면 명령줄 형식이 불편할 수 있습니다. 이 경우 Gulp와 함께 사용하는 것이 좋습니다.
꿀꺽꿀꺽

Gulp와 함께 사용하면 Browserify는 특정 프로젝트에만 설치됩니다.

npm install browserify --save-dev

프로젝트의 package.json에 저장하려면 --save-dev를 추가하는 것이 좋습니다.

다음은 gulpfile.js의 일부입니다. 간단한 예는 다음과 같습니다.

var gulp = require("gulp");
var browserify = require("browserify");
var sourcemaps = require("gulp-sourcemaps");
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');

gulp.task("browserify", function () {
 var b = browserify({
  entries: "./javascripts/src/main.js",
  debug: true
 });

 return b.bundle()
  .pipe(source("bundle.js"))
  .pipe(buffer())
  .pipe(sourcemaps.init({loadMaps: true}))
  .pipe(sourcemaps.write("."))
  .pipe(gulp.dest("./javascripts/dist"));
});

可以看到,Browserify是独立的,我们需要直接使用它的API,并将它加入到Gulp的任务中。

在上面的代码中,debug: true是告知Browserify在运行同时生成内联sourcemap用于调试。引入gulp-sourcemaps并设置loadMaps: true是为了读取上一步得到的内联sourcemap,并将其转写为一个单独的sourcemap文件。vinyl-source-stream用于将Browserify的bundle()的输出转换为Gulp可用的vinyl(一种虚拟文件格式)流。vinyl-buffer用于将vinyl流转化为buffered vinyl文件(gulp-sourcemaps及大部分Gulp插件都需要这种格式)。

这样配置好之后,直接运行gulp browserify就可以得到结果了,可能像这样:

2015728152450337.png (526×74)

如果你的代码比较多,可能像上图这样一次编译需要1s以上,这是比较慢的。这种时候,推荐使用watchify。它可以在你修改文件后,只重新编译需要的部分(而不是Browserify原本的全部编译),这样,只有第一次编译会花些时间,此后的即时变更刷新则十分迅速。

有关更多Browserify + Gulp的示例,请参考Gulp Recipes。
特性及简要原理

使用Browserify来组织JavaScript,有什么要注意的地方吗?

要回答这个问题,我们先看看Browserify到底做了什么。下面是一个比较详细的例子。

项目内现在用到2个.js文件,它们存在依赖关系,其内容分别是:
name.js

module.exports = "aya";

main.js

var name = require("./name");

console.log("Hello! " + name);

然后对main.js运行Browserify,得到的bundle.js的文件内容是这样的:
bundle.js

(function e(t, n, r) {
 // ...
})({
 1: [function (require, module, exports) {
  var name = require("./name");

  console.log("Hello! " + name);
 }, {"./name": 2}],
 2: [function (require, module, exports) {
  module.exports = "aya";
 }, {}]
}, {}, [1])

//# sourceMappingURL=bundle.js.map

请先忽略掉省略号里的部分。然后,它的结构就清晰多了。可以看到,整体是一个立即执行的函数(IIFE),该函数接收了3个参数。其中第1个参数比较复杂,第2、3个参数在这里分别是{}和[1]。
模块map

第1个参数是一个Object,它的每一个key都是数字,作为模块的id,每一个数字key对应的值是长度为2的数组。可以看出,前面的main.js中的代码,被function(require, module, exports){}这样的结构包装了起来,然后作为了key1数组里的第一个元素。类似的,name.js中的代码,也被包装,对应到key2。

数组的第2个元素,是另一个map对应,它表示的是模块的依赖。main.js在key1,它依赖name.js,所以它的数组的第二个元素是{"./name": 2}。而在key2的name.js,它没有依赖,因此其数组第二个元素是空Object{}。

因此,这第1个复杂的参数,携带了所有模块的源码及其依赖关系,所以叫做模块map。
包装

前面提到,原有的文件中的代码,被包装了起来。为什么要这样包装呢?

因为,浏览器原生环境中,并没有require()。所以,需要用代码去实现它(RequireJS和Sea.js也做了这件事)。这个包装函数提供的3个参数,require、module、exports,正是由Browserify实现了特定功能的3个关键字。
缓存

第2个参数几乎总是空的{}。它如果有的话,也是一个模块map,表示本次编译之前被加载进来的来自于其他地方的内容。现阶段,让我们忽略它吧。
入口模块

第3个参数是一个数组,指定的是作为入口的模块id。前面的例子中,main.js是入口模块,它的id是1,所以这里的数组就是
[1]。数组说明其实还可以有多个入口,比如运行多个测试用例的场景,但相对来说,多入口的情况还是比较少的。
实现功能

还记得前面忽略掉的省略号里的代码吗?这部分代码将解析前面所说的3个参数,然后让一切运行起来。这段代码是一个函数,来自于browser-pack项目的prelude.js。令人意外的是,它并不复杂,而且写有丰富的注释,很推荐你自行阅读。
所以,到底要注意什么?

到这里,你已经看过了Browserify是如何工作的。是时候回到前面的问题了。首先,在每个文件内,不再需要自行包装。

你可能已经很习惯类似下面这样的写法:

;(function(){
 // Your code here.
}());

但你已经了解到,Browserify的编译会将你的代码封装在局部作用域内,所以,你不再需要自己做这个事情,像这样会更好:

// Your code here.

类似的,如果你想用"use strict";启用严格模式,直接写在外面就可以了,这表示在某个文件的代码范围内启用严格模式。

其次,保持局部变量风格。我们很习惯通过window.jQuery和window.$这样的全局变量来访问jQuery这样的库,但如果使用Browserify,它们都应只作为局部变量:

var $ = require("jquery");

$("#alice").text("Hello!");

这里的$就只存在于这个文件的代码范围内(独立的作用域)。如果你在另一个文件内要使用jQuery,需要按照同样的方式去require()。

然而,新的问题又来了,既然jQuery变成了这种局部变量的形式,那我们熟悉的各种jQuery插件要如何使用呢?
browserify-shim

你一定熟悉这样的jQuery插件使用方式:

<script src="jquery.js"></script>
<script src="jquery.plugin.js"></script>
<script>
 // Now the jQuery plugin is available.
</script>

很多jQuery插件是这样做的:默认window.jQuery存在,然后取这个全局变量,把自己添加到jQuery中。显然,这在Browserify的组织方式里是没法用的。

为了让这样的“不兼容Browserify”(其实是不兼容CommonJS)的JavaScript模块(如插件)也能为Browserify所用,于是有了browserify-shim。

下面,以jQuery插件jquery.pep.js为例,请看browserify-shim的使用方法。
使用示例

安装browserify-shim:

npm install browserify-shim --save-dev

然后在package.json中做如下配置:

"browserify": {
 "transform": [ "browserify-shim" ]
},
"browser": {
 "jquery.pep" : "./vendor/jquery.pep.js"
},
"browserify-shim": {
 "jquery.pep" : { "depends": ["jquery:jQuery"] }
}

最后是.js中的代码:

var $ = require("jquery");
require("jquery.pep");

$(".move-box").pep();

完成!到此,经过Browserify编译后,将可以正常运行这个jQuery插件。

这是一个怎样的过程呢?

在本例中,jQuery使用的是npm里的,而jquery.pep.js使用的是一个自己下载的文件(它与很多jQuery插件一样,还没有发布到npm)。查看jquery.pep.js源码,注意到它用了这样的包装:

;(function ( $, window, undefined ) {
 // ...
}(jQuery, window));

可以看出,它默认当前环境中已存在一个变量jQuery(如果不存在,则报错)。package.json中的"depends": ["jquery:jQuery"]是为它添加依赖声明,前一个jquery表示require("jquery"),后一个jQuery则表示将其命名为jQuery(赋值语句)。这样,插件代码运行的时候就可以正常找到jQuery变量,然后将它自己添加到jQuery中。

实际上,browserify-shim的配置并不容易。针对代码包装(尽管都不兼容CommonJS,但也存在多种情况)及使用场景的不同,browserify-shim有不同的解决方案,本文在此只介绍到这。

关于配置的更多说明,请参照browserify-shim官方文档。更多参考可以查看browserify shim recipes。此外,如果你觉得browserify-shim有些难以理解或者对它的原理也有兴趣,推荐阅读这篇Stack Overflow上的回答

当然,对于已经处理了CommonJS兼容的库或插件(比如已经发布到npm),browserify-shim是不需要的。
其实还有的更多transform

在前面browserify-shim的例子中,"browserify": {"transform": [ "browserify-shim" ]}其实是Browserify的配置。可以看出,browserify-shim只是Browserify的其中一种transform。在它之外,还有很多的transform可用,分别应对不同的需求,使Browserify的体系更为完善。

比如,还记得本文引言里的Bower吗?debowerify可以让通过Bower安装的包也可以用require()引用。npm和bower同为包管理工具,Browserify表示你们都是我的翅膀。
一点提示

Browserify是静态分析编译工具,因此不支持动态require()。例如,下面这样是不可以的:

var lang = "zh_cn";
var i18n = require("./" + lang);

文档资料

有关Browserify更详细的说明文档,请看browserify-handbook
结语

我觉得Browserify很有趣,它用了这样一个名字,让你觉得它好像只是一个Node的浏览器端转化工具。为此,它还完成了Node中大部分核心库的浏览器端实现。但实际上,它走到了更远的地方,并在JavaScript模块化开发这个重要的领域中,创立了一个全新的体系。

喜欢CommonJS的简洁风格?请尝试Browserify!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.