了解Browserify
Browserify是一个Javascript的库,可以用来把多个Module打包到一个文件中,并且能很好地应对Modules之间的依赖关系。而Module是封装了属性和功能的单元,是一个Javascript对象,Modules之间可以相互依赖。某种程度上来说,Browserify模仿了Node.js加载Module的方式。一个js文件包含一个Module。所以,Browserify通过读取文件来加载该文件内的Module。
【module的写法】
'use strict';
exports.save = function(tasks){};
exports.load = function(){};
exports.clear = function(){};
还可以这么写:
'use strict';
module.exports = {
save: function(tasks){},
load: function(){},
clear: function(){}
};
【module的缓存】
1、单例模式缓存
module a
exports.value = "original";
module b
var a = require('./a');
a.value = "changed";
console.log(a.value);//changed
module c
var a = require('./a');
console.log(a.value);//original
module c中的a.value值之所以是original,是因为module c对module a有依赖,而且依赖的是缓存。所以,在默认情况下,module是有缓存的,也可以理解成单例模式。
2、实例模式缓存
还可以通过构造函数来创建一个module。
module a
module.exports = function(){
this.value = "original value";
};
module b
var A = require('./a');
var a = new A();
a.value = "changed";
console.log(a.value);//changed
module c
var A = require('./a');
var a = new A();
console.log(a.value);//original
【准备工作】
- 安装Node.js
- 安装Browserify:npm install -g browserify
【明确目标】
- app这个module包含了和视图交互的逻辑,是整个程序的entry point
- app这个module依赖tasks这个module,tasks这个module用来管理task list
- taskRender这个module用来渲染页面,taskData这个module用来保存加载有关task list的数据
【文件结构】
.....css/
..........tasks.css
.....js/
..........data/
...............taskData.js
..........renderers/
...............taskRenderer.js
..........tasks.js
..........app.js
.....index.html
【代码实现】
文件结构有了,module的写法也搞清楚了,接下来就实现一遍。
① taskData.js 是用来处理数据的一个module
'use strict';
var STORE_NAME = "tasks";
exports.save = function(tasks){
localStorage.setItem(STORE_NAME, JSON.stringify(tasks));
};
exports.load = function(){
var storedTasks = localStorage.getItem(STORE_NAME);
if(storedTasks){
return JSON.parse(storedTasks);
}
return [];
};
exports.clear = function(){
localStorage.removeItem(STORE_NAME);
};
② taskRenderer.js 是用来处理页面相关的一个module
'use strict';
var $ = require('jquery');
var taskTemplate = '<li class="task"><input class="complete" type="checkbox" /><input class="description" type="text" /></li>';
//返回一段带值的html
//task是传入的一个object对象
function _renderTask(task){
var $task = $(taskTemplate);
if(task.complete){
$task.find(".complete").attr("checked", "checked");
}
$task.find(".description").val(task.description);
return $task;
}
exports.renderTasks = function(tasks){
//遍历任务获得带值html的数组
var elementArray = $.map(tasks, _renderTask);
$("#task-list")
.empty()
.append(elementArray);
};
exports.renderNew = function(){
var $taskList = $("#task-list");
$taskList.prepend(_renderTask({}));
}
③ tasks.js 用到了以上2个module
'use strict';
var $ = require('jquery');
var taskData = require('./data/taskData');
var taskRenderer = require('./renderers/taskRenderer');
exports.add = function () {
taskRenderer.renderNew();
};
exports.remove = function (clickEvent) {
var taskElement = clickEvent.target;
$(taskElement).closest(".task").remove();
};
exports.clear = function(){
taskData.clear();
exports.render();
};
exports.save = function(){
var tasks=[];
$("#task-list .task").each(function(index, task){
var $task = $(task);
tasks.push({
complete: $task.find(".complete").prop('checked'),
description: $task.find(".description").val()
});
});
taskData.save(tasks);
};
exports.cancel = function(){
exports.render();
};
exports.render = function(){
taskRenderer.renderTasks(taskData.load());
};
④ app.js 只需要和tasks.js打交道就可以
'use strict';
var $ = require('jquery');
var tasks =require('./tasks');
function _addTask(){
tasks.add();
}
function _deleteAllTasks(){
tasks.clear();
}
function _saveChanges(){
tasks.save();
}
function _cancelChanges(){
tasks.cancel();
}
function _deleteTask(clientEvent){
tasks.remove(clientEvent);
}
function _registerEventHandlers(){
$('#new-task-button').on("click", _addTask);
$('#delete-all-button').on("click", _deleteAllTasks);
$('#save-button').on("click",_saveChanges);
$('#cancel-button').on("click", _cancelChanges);
$('#task-list').on("click", ".delete-button", _deleteTask);
}
_registerEventHandlers();
tasks.render();
⑤ 使用browserify把所有module捆绑到一个js文件中去:
browserify src\js\app.js -o src\js\app.bundle.js
⑥ index.html 只需要引用src\js\app.bundle.js就可以
<!DOCTYPE html>
<html>
<head>
<title>Task List</title>
<link rel="stylesheet" href="css/tasks.css">
</head>
<body>
<header>
<h1>TaskList</h1>
</header>
<div class="toolbar">
<button id="new-task-button">New Task</button>
<button id="delete-all-button">Delete All</button>
</div>
<div id="content">
<ul id="task-list">
</ul>
<ul id="log-list">
</ul>
</div>
<div class="toolbar">
<button id="save-button">Save</button>
<button id="cancel-button">Cancel</button>
</div>
<script src="js/app.bundle.js"></script>
</body>
</html>
【如果有很多文件,调试时出错】
当有很多文件的时候,调试出错,使用Source Map可以方便找到出错的文件和出错的地方。
现在,有了app.bundle.js文件,以及有了app.js, tasks.js, taskRenderer.js, taskData.js文件们,我们可以在app.bundle.js和其它js文件中创建一个Souce Map.
browserify src\js\app.js -o src\js\app.bundle.js --debug
这样,会在app.bundle.js文件最后面追加上类似//# sourceMappingURL=data:application/json;
,这样在调试的时候会很容易找到出错的文件和出错的位置。
【修改文件】
如果此时修改某个js文件呢?我们还需要使用browserify把所有的module依赖关系捆绑到一个文件中,执行如下的命令:
browserify src\js\app.js -o src\js\app.bundle.js
解决思路:Watchify为此而生,当发现有文件变化,自动运行Browserify。
全局安装Watchify:npm install -g watchify
在命令行窗口运行Watchify命令:watchify src\js\app.js -o src\js\app.bundle.js --debug -v
此时保持命令窗口打开着。
修改某个文件,并保存,发现命令窗口会自动运行:watchify src\js\app.js -o src\js\app.bundle.js --debug -v
【Grunt Browserify】
Grunt是Javascript Task Runner,也是运行在Node.js之上。
如何安装Grunt?
- npm install -g grunt-cli
- npm install grunt --save-dev
检测版本?
grunt --version
在哪个文件中配置?
一般在根目录下的Gruntfile.js
Grunt与Browserify的结合?
npm install grunt-browserify --save-dev
在根目录下的Gruntfile.js文件:
module.exports=function(grunt){
//配置
grunt.initConfig({
browserify: {
app: {
src: 'templates/src/js/app.js',
dest: 'templates/src/js/app.bundle.js',
options: {
browserifyOptions:{
debug: true
}
}
}
}
});
//加载其它module/plugins
grunt.loadNpmTasks('grunt-browserify');
//定义task
grunt.registerTask('default',['browserify']);
}
【Grunt Watch】
使用了Grunt以及用Gruntfile.js进行配置之后,每次有文件变化,我们需要在命令行窗口输入gulp命令。能不能自动为我们运行gulp命令呢?
Grunt Watch出场。
如何安装Grunt Watch?
npm install grunt-contrib-watch --save-dev
修改Gruntfile.js文件
module.exports=function(grunt){
//配置
grunt.initConfig({
browserify: {
app: {
src: 'templates/src/js/app.js',
dest: 'templates/src/js/app.bundle.js',
options: {
browserifyOptions:{
debug: true
}
}
}
},
watch: {
app: {
files: ['templates/src/js/*/*.js'],
tasks: ['browserify']
}
}
});
//加载其它module/plugins
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch');
//定义task
grunt.registerTask('default',['browserify']);
}
在命令行窗口输入:grunt watch
现在,修改templates/src/js中的任何js文件,会自动运行browserify命令。
【Grunt Connect】
Grunt Connect可以让我们搭建一个web server。
如何安装?
npm install grunt-contrib-connect --save-dev
修改Gruntfile.js文件
module.exports=function(grunt){
//配置
grunt.initConfig({
browserify: {
app: {
src: 'templates/src/js/app.js',
dest: 'templates/src/js/app.bundle.js',
options: {
browserifyOptions:{
debug: true
}
}
}
},
watch: {
app: {
files: ['templates/src/js/*/*.js'],
tasks: ['browserify']
}
},
connect: {
app: {
options: {
port: 9001,
base: 'templates/src'
}
}
}
});
//加载其它module/plugins
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-connect');
//定义task
grunt.registerTask('default',['browserify']);
grunt.registerTask('serve',['browserify:app', 'connect:app', 'watch:app']);
}
在命令行窗口输入:grunt serve
在浏览器窗口输入:localhost:9001
【Connect Live Reload】
现在,可以在浏览器中输入localhost:9001浏览到网页内容,此时,如果某个文件有变化,我们需要重新刷新浏览器。web server可以有自动刷新的功能吗?
Connect Live Reload就是解决这个问题的。
如何安装?
npm install connect-livereload --save-dev
修改Gruntfile.js文件
module.exports=function(grunt){
//配置
grunt.initConfig({
browserify: {
app: {
src: 'templates/src/js/app.js',
dest: 'templates/src/js/app.bundle.js',
options: {
browserifyOptions:{
debug: true
}
}
}
},
watch: {
app: {
files: ['templates/src/js/*/*.js'],
tasks: ['browserify'],
options: { //为保持web server 的自动刷新而设置
livereload: true
}
}
},
connect: {
app: {
options: {
port: 9001,
base: 'templates/src',
middleware: function(connect, options, middlewares){//为保持web server 的自动刷新而设置
middlewares.unshift(require('connect-livereload')());
return middlewares;
}
}
}
}
});
//加载其它module/plugins
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-connect');
//定义task
grunt.registerTask('default',['browserify']);
grunt.registerTask('serve',['browserify:app', 'connect:app', 'watch:app']);
}
在命令行窗口输入:grunt serve
在浏览器中打开:http://localhost:9001/
修改某个文件,浏览器中自动有变化。
了解Browserify的更多相关文章
- Vue.js——60分钟browserify项目模板快速入门
概述 在之前的一系列vue.js文章,我们都是用传统模式引用vue.js以及其他的js文件的,这在开发时会产生一些问题. 首先,这限定了我们的开发模式是基于页面的,而不是基于组件的,组件的所有代码都直 ...
- 前端构建工具的用法—grunt、gulp、browserify、webpack
随着前端项目的飞速发展,项目越来越大.文件越来越多,前端工程化的工具也越来越多.下面介绍目前最流行的四种构建工具——grunt.gulp.browserify.webpack 所有的构建工具都是基于N ...
- gulp启动一个小型web服务器配置&browserify(require)
var gulp = require('gulp'), connect = require('gulp-connect'), // 运行live reload服务器 browserify = requ ...
- browserify压缩合并源码反编译
最近在学习钉钉(一个协作应用)桌面应用的前端源码时候,发现其js源码是用browserify做模块开发.于是想还原其源码的原本的目录结构,学习它的目录分类以及业务划分. 前言 用过browserify ...
- browserify学习总结
前言 在未接触browserify,虽然我知道它是一个前端构建工具,但还是有几个疑问: 1. browserify出现的日期? 2. 能构建哪些文件? 3. 附加的browserify代码体积是多大? ...
- gulp/grunt和browserify/webpack的区别
Gulp应该和Grunt比较,他们的区别我就不说了,说说用处吧.Gulp / Grunt 是一种工具,能够优化前端工作流程.比如自动刷新页面.combo.压缩css.js.编译less等等.简单来说, ...
- angular项目总结——angular + browserify + gulp + bower + less 架构分享
一眨眼,快三个月没有写博客了.一直在为自己没有写博客而懊恼,忙过这段时间,好好总结一下. 新项目主要是自己一个人在写,先搭建了一个初步的架构,用了我并不熟悉的angular,这个过程中,慢慢也熟悉了a ...
- browserify使用手册
简介 这篇文档用以说明如何使用browserify来构建模块化应用 browserify是一个编译工具,通过它可以在浏览器环境下像nodejs一样使用遵循commonjs规范的模块化编程. 你可以使用 ...
- 使用Gulp和Browserify来搭建React应用程序
对React有一定了解之后,我们知道,需要把JSX文件转换成JS文件,组件需要导入导出.本篇就体验使用Gulp把JSX文件转换成JS文件,使用Browserify来把组件捆绑到一个文件并理顺组件之间的 ...
- 使用Gulp和Browserify创建多个绑定文件
Browserify是一个Javascript的绑定工具,帮助我们理顺module之间的依赖关系.Gulp用来优化workflow.两者的共同点都是使用流,但在使用流方面也有不同之处: Browser ...
随机推荐
- Ubuntu遇到Please ensure that adb is correctly located at '...adb.exe' and can be executed 问题解决方法
上次我们在SDK更新的到最新的Android L版本之后,我发现我的ADT和android指定的版本不对应,我的ADT是22版本的,android L需要23版本以上的,版本不对应的话就无法加载这个S ...
- android studio小技巧
1. 为了防止乱码,请将 android studio 右下角编码设置成 UTF-8 2. Ctri + Q 查看api 3 Ctri + Shift +U 大小写互换 4 Ctrl + Alt + ...
- JDBC常用接口详解
JDBC中常用接口详解 ***DriverManager 第一.注册驱动 第一种方式:DriverManager.registerDriver(new com.mysql.jdbc.Driver()) ...
- ubuntu 14.04 编译内核出现unable to locate package ncurses-devel 问题的解决
http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece7631046893b4c4380146d96864968d4e414c422461614 ...
- 关于在xml文件中的 error: invalid symbol: 'switch' 错误
在xml布局文件中使用Switch控件时,出现error: invalid symbol: 'switch'报错,代码如下: <Switch android:id="@+id/swit ...
- networkx的绘图中文显示方块问题
修改matplotlibrc文件 font.family : sans-serif #打开该选项 font.sans-serif : Microsoft YaHei , Bitstream Vera ...
- 调用数据库函数CallableStatement
- 在VLFEAT中mat类型图片转换成constant float* 来进行vl_dsift_process
How to convert an OpenCV cv::Mat into a float* that can be fed into Vlfeat vl_dsift_process: Mat mat ...
- [ASE][Daily Scrum]11.17
这两天感冒了没有第一时间更新blog和tfs,给大家抱歉了! 上周五我们已经将服务器搭建完成并成功通讯,周六周日大家非常给力的完成了很多内容! View Shilin Liu 处理来自服务器的数据 显 ...
- SQL Server 利用游标解决Tempdb究极竞争-DBA-程序员需知
SQL Server tempdb分配竞争算是DBA老生常谈的问题了,几乎现在所有的DBA都知道多建几个文件来解决/缓解问题.但是深层次的的竞争依旧不可避免.这里给大家剖析下游标在tempdb中的特点 ...