在node项目中使用Sea.js

文章目录
  1. 1. 前言
  2. 2. 配置
    1. 2.1. 下载seajs
    2. 2.2. 项目结构
    3. 2.3. 概念说明
    4. 2.4. 静态资源配置
    5. 2.5. sea-config.js
    6. 2.6. home.js
    7. 2.7. 引入js文件
  3. 3. CMD模块化
    1. 3.1. 不封装
    2. 3.2. jquery封装
    3. 3.3. 依赖jquery的插件封装
    4. 3.4. 普通插件封装
  4. 4. layer的坑
    1. 4.1. 不封装
    2. 4.2. 封装
    3. 4.3. 不完美解决办法
  5. 5. seajs模块加载顺序
  6. 6. 后记
  7. 7. 书签

前言

Sea.js 追求简单、自然的代码书写和组织方式,具有以下核心特性:

  • 简单友好的模块定义规范:Sea.js遵循CMD规范,可以像Node.js一般书写模块代码。
  • 自然直观的代码组织方式:依赖的自动加载、配置的简洁清晰,可以让我们更多地享受编码的乐趣。

Sea.js还提供常用插件,非常有助于开发调试和性能优化,并具有丰富的可扩展接口。

配置

下载seajs

seajs官方下载:http://seajs.org/docs/#downloads

项目结构

概念说明

下面明确几个概念,方便接下来的描述:
1、/(网站根目录),是项目目录nodebase
2、虚拟路径,是node把某个文件(夹)转化之后,该文件(夹)的相对于/的路径。
3、访问路径,是通过浏览器url访问的路径。

虚拟路径不一定是访问路径,访问路径不一定是虚拟路径。因为,只有我们指定的资源、指定的路径是开放给用户访问的。

静态资源配置

1
2
3
// 把文件夹中的内容添加到网站根目录下,静态文件务必添加,否则访问不到
app.use(express.static(path.join(__dirname, 'bower_components')));
app.use(express.static(path.join(__dirname, 'public')));

在node项目的入口文件app.js中,加入如上配置,那么,bower_components、public两个文件夹的虚拟路径都变成了/,访问路径都变成了/

1
2
3
4
5
// 静态文件目录
var staticDir = path.join(__dirname, 'public');
// 虚拟目录
app.use('/dist', express.static(staticDir));
app.use('/public', express.static(staticDir));

在node项目的入口文件app.js中,加入如上配置,那么,public文件夹的虚拟路径就变成了/dist/public,访问路径就变成了/dist/public

通过上面两个配置,可以看出,静态资源的虚拟路径和访问路径是相同的。

sea-config.js

1
2
3
4
5
6
7
8
9
seajs.config({
//base: '../',
base: window.host + '/',
alias: {
'jquery': 'seajs/jquery/jquery.min.js',
'layer': 'seajs/layer/layer.js',
'swiper': 'Swiper/dist/js/swiper.min.js'
}
});

如果base的值使用相对路径../,那么页面引入依赖的js文件的时候,就是相对于页面文件的虚拟路径。

1
app.set('views','./views');// 页面目录配置

举个例子,在app.js中使用了页面目录配置,views文件夹虚拟路径变成了/。注意,views文件夹依然没有访问路径。

views文件夹的目录结构如下:

1
2
3
4
views
|-weixin
| |-home.html
|-index.html

在路由转发中,index.html和home.html的虚拟路径分别如下:

1
2
3
4
5
6
res.render('index',{
title: 'index'
});
res.render('weixin/home',{
title: 'home'
});

在index.html中引入sea-config.js,在加载依赖的js文件的时候,会在index.html的基础上向上一层寻找。因为index.html所在的虚拟路径为/,没有上一层,所以肯定找不到js文件。

而home.html所在的虚拟路径为/weixin/,向上一层寻找,是虚拟路径/。而静态文件的虚拟路径都是/,刚好可以找到需要的js文件。

鉴于相对路径的差异问题,base最好使用绝对路径,配置在全局config.js中。

home.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
seajs.use(['jquery','layer'],function($,layer){
var index = {
init:function(){
this.saveData();
this.bindEvent();
},
saveData: function(){
if(window.localStorage){
var x = window.localStorage.userInfo? JSON.parse(window.localStorage.userInfo):{};
if((x.unionid == undefined) || (x.unionid == "undefined")){
var temp = {
unionid: $('#unionid').val(),
openid: $('#openid').val(),
nickname: $('#nickname').val(),
headimgurl:$ ('#headimgurl').val()
};
window.localStorage.userInfo = JSON.stringify(temp);
}
}
},
bindEvent:function(){
layer.alert('layer');
}
}
index.init();
});

引入js文件

1
2
3
4
5
6
<script>
window.host = '<%= host%>';
</script>
<script src="/seajs/seajs-1.3.1/dist/sea.js"></script>
<script src="/seajs/sea-config.js"></script>
<script src="/js/weixin/home.js"></script>

CMD模块化

不封装

因为seajs遵循CMD规范,所以遵循CMD规范的插件,比如swiper,引入后就可以使用。

jquery封装

jquery遵循AMD规范,需要封装一下,使其符合CMD规范才可以使用,否则会报错。

1
2
3
define(function(require, exports, module) {
// 模块化jquery源码
});

依赖jquery的插件封装

有些插件,是在jquery的基础上的开发的,需要先引入jquery。

1
2
3
4
define(function(require, exports, module) {
var $ = require('jquery');
// 依赖jquery的模块化代码
});

另外一种方法:

1
2
3
4
5
define(function(require, exports, module) {
return function($){
// 依赖jquery的模块化代码
}
});

这种方法在使用模块前需要先传入jquery进行初始化。

普通插件封装

如果是未模块化的插件(普通js代码),需要暴露对应的接口。

1
2
3
4
5
6
7
8
9
10
11
define(function(require, exports, module) {
var $ = require('jquery');
var voidking = {
init: function(){
// 未模块化代码
var height = $(document).height();
console.log(height);
}
};
module.exports = voidking;
});

在使用模块前需要调用init方法初始化。

layer的坑

不封装

不对layer.js进行封装,直接引入时,会报错jQuery is not defined
需要说明的是,在使用layer-mobile.js的时候,不需要封装就可以正常使用。

封装

由上面的报错,可以看出,layer.js需要依赖jquery,那就封装一下,引入jquery吧!

1
2
3
4
define(function(require, exports, module) {
var jQuery = require('jquery');
// layer.js代码
});

然后,错误就变成了layer.alert is not a function
在控制台输入layer,可以看到layer是一个对象。

啊嘞,layer对象明明包含了一个alert方法!!!为啥不能调用捏?

不甘心的小编,又尝试了很多其他的封装方法,依然无法使用。

不完美解决办法

layer的作者贤心说,layer是CMD规范的。那么,理论上直接引入就可以使用。但是,错误当道,jQuery is not defined。那么问题的关键,就是给layer.js引入jquery。

使用封装的办法,引入jquery,经过测试,行不通。

如果直接把jquery源码粘贴到layer.js文件中,是否可以呢?经过测试,确实可以!!!

好吧,这个坑总算是填上了。虽然不够完美,但是确实是个有效的方法!如果有更好的解决的办法,希望能留言告诉我,谢谢。

seajs模块加载顺序

1、从seajs.use方法入口,开始加载use到的模块。
2、use到的模块这时mod缓存当中一定是不存在的,seajs创建一个新的mod,赋予一些初始的状态。
3、执行mod.load方法。
4、一堆逻辑之后走到seajs.request方法,请求模块文件。模块加载完成之后,执行define方法。
5、define方法分析提取模块的依赖模块,保存起来,缓存factory但不执行。
6、模块的依赖模块再被加载,如果继续有依赖模块,则继续加载,直至所有被依赖的模块都加载完毕。
7、所有的模块加载完毕之后,执行use方法的callback。
8、模块内部逻辑从callback开始执行,require方法在这个过程当中才被执行。
PS: define方法纯粹只是分析模块、存储模块,并没有执行模块。require方法就是根据id在define定义存储的模块缓存中找到相应的模块,并执行它,获得模块定义返回的方法。

后记

也许,参加Sea.js的社区维护也是一件很好玩的事情。又多了很多许多需要学习的东西,路漫漫其修远兮!

书签

Seajs简易文档
http://yslove.net/seajs/

快速上手seajs——简单易用Seajs
http://www.tuicool.com/articles/3uIZzy

seajs base配置
http://www.tuicool.com/articles/3Eb6Fj

jQuery 插件的模块化
https://lifesinger.wordpress.com/jquery-plugins-modulization/

seajs 加载Jquery的遇到问题?
https://www.zhihu.com/question/21703739

如何改造现有文件为 CMD 模块
https://github.com/seajs/seajs/issues/971

CMD 模块定义规范
https://github.com/seajs/seajs/issues/242

社区
https://github.com/seajs/seajs/issues/271

前端模块化开发那点历史
https://github.com/seajs/seajs/issues/588

如何参与开发
https://github.com/seajs/seajs/issues/276

Develop A Package
http://spmjs.io/documentation/develop-a-package

高富帅seajs使用示例及spm合并压缩工具露脸
http://www.zhangxinxu.com/wordpress/2012/07/seajs-node-nodejs-spm-npm/

Hello Sea.js
http://island205.github.io/HelloSea.js/index.html

从零开始编写自己的JavaScript框架(一)
http://www.ituring.com.cn/article/48461

Javascript模块化编程(一):模块的写法
http://www.ruanyifeng.com/blog/2012/10/javascript_module.html

JavaSript模块规范 - AMD规范与CMD规范介绍
http://blog.chinaunix.net/uid-26672038-id-4112229.html

该如何理解AMD ,CMD,CommonJS规范
http://www.cnblogs.com/qianshui/p/5216580.html?utm_source=tuicool&utm_medium=referral
http://www.tuicool.com/articles/MVrMBrI

(function($){…})(jQuery)是什么意思
http://blog.csdn.net/rambo_china/article/details/7742321

深入探寻seajs的模块化与加载方式
http://www.jb51.net/article/64024.htm

seajs模块加载机制
http://www.jianshu.com/p/1245af09383e

SeaJS中jQuery插件模块化及其调用方式
http://my.oschina.net/briviowang/blog/208587

seajs模块化jQuery与jQuery插件
http://julabs.com/blog/seajs-jquery-and-plugins/

Sea.js 手册与文档
http://www.zhangxinxu.com/sp/seajs/docs/zh-cn/module-definition.html