最近使用seajs
开发的时候遇到一些问题,在此记录一下分享给大家。
模块定义
遵循seajs规范,模块化的js需要使用define函数定义,一个js文件即一个模块。define(id, deps, factory) 函数包括三个参数:id、deps、factory,其中id是模块的id,deps是模块的依赖。
模块ID定义
一般我们用js文件的路径
来定义模块,如下:
define('src/mod1/demo', function(require, exports, module) {
...
});
在页面引入模块的时候使用seajs.use函数,需要使用模块的 id 引入模块,如下:
seajs.use(['src/mod1/demo'],function (demo) {
...
});
此时不得不说seajs中的模块路径规则,seajs要求模块的ID与路径匹配。 如果 seajs.use 或 require 引用的是不具名模块(未定义了 ID 的模块),则只需要填入模块文件的相对路径即可。 但是如果是引用具名模块(定义了 ID 的模块),会把 ID 和 seajs.use 函数中引用的路径名进行匹配,如果一致,则正确执行模块返回结果。反之,则返回 null。所以,如果想要定义模块的ID,最好与其绝对路径保持一致。
如果想随意定义模块ID,可以在页面中单独用<script>
标签引入该模块文件,也可以通过seajs.use函数引入模块,但是这样做违背了seajs按需加载的机制,让js模块化失去意义。
模块间依赖注入
模块之间可以相互依赖,deps是模块的依赖,在deps中添加模块的ID,在加载模块之前会预先加载deps中的资源。如果define函数中deps参数为空,则在该模块被加载之前,会把整个js文件toString
,解析为字符串后通过正则匹配,将所有的require()函数中的模块ID以String
形式取出来,预先加载资源。
所以当deps参数为空时,不管require()函数出现何处(甚至是注释),都会被当做模块需要的资源预先加载。可想而知,此时require()也不可带变量,这样是获取不到资源的。
现针对上面的列举两种情况,逻辑一致,都是动态给 test2 赋值,但是得到结果却不一致。
1)第一种情况如下,会预先加载./mod1/test1.js
,./mod1/test2.js
,./mod2/test2.js
。得到的test2为./mod1/test2'
define(function(require, exports, module) {
'use strict'
var test1 = require('./mod1/test1')
var test2
if(test1){
test2 = require('./mod1/test2')
}else{
test2 = require('./mod2/test2')
}
...
});
2)第二种情况如下,只会预先加载./mod1/test1.js
,故得到的test2为null
。
define(function(require, exports, module) {
'use strict'
var test1 = require('./mod1/test1')
var path
if(test1){
path = './mod1/test2'
}else{
path = './mod2/test2'
}
var test2 = require(path)
...
});
使用seajs-combo进行js资源合并
在前端工程中,经常会将前端资源合并,从而达到减少HTTP请求而提升前端性能。seajs也支持资源合并,使用 seajs-combo 插件,配合服务器的 nginx-http-concat 服务,可自动对同一批次的多个模块进行合并下载。
使用combo把模块化的js合并起来,要求每一个模块必须
定义ID,遵循路径即ID的原则。
虽然seajs的规范比较简单且容易遵循,但是在一个前端工程中,往往开发环境的文件路径,和经过打包之后的实际环境的文件路径,不一定是一致的。
注意
:combo功能需要配合nginx使用
使用FIS3进行打包
FIS3官网是这样介绍:FIS3 是面向前端的工程构建工具。解决前端工程中性能优化、资源加载(异步、同步、按需、预加载、依赖管理、合并、内嵌)、模块化开发、自动化工具、开发规范、代码部署等问题。
个人简单理解为一款前端打包工具。
FIS3支持cmd的模块化开发,帮我们解决模块路径的问题,使用我们在开发过程中不需再考虑头疼的路径问题,也可以完美的结合combo插件进行前端资源合并。安装FIS3参考官网,cmd插件参考使用文档
fis-conf.js配置文件
安装完FIS3和fis3-hook-cmd后,在工程根目录下创建FIS3配置文件fis-conf.js
project
│ fis-conf.js
│ index.html
│ ...
│
└─── src
│ │
│ └─── mod1
│ │ │ test1.js
│ │ │ test2.js
│ │ │ ...
│ │
│ └─── mod2
│ │ │ test3.js
│ │ │ test4.js
│ │ │ ...
│ │
│ └─── ...
│
└─── ...
关于FIS3配置文件,需要注意标明那些文件是模块化的js文件
fis.match('/src/**.js', { // 需要对目标文件设置 isMod 属性,说明这些文件是模块化代码。
isMod: true
})
fis.hook('cmd', {
baseUrl: '.' // 默认为 . 即项目根目录。用来配置模块查找根目录。
})
在更目录下打开命令行,使用FIS3打包代码,可参考FIS3命令。
fis3 release -d ./dist
下图为index.html打包前后的对比,可以看到打包前seajs.use中模块ID写为相对路径,而打包之后变为绝对路径。
下图为demo.js打包前后的对比,可以看到打包前模块ID和模块依赖未定义,require()函数中路径为相对路径。打包之后,模块ID被定义为文件的绝对路径,原文件中require函数中的资源ID也变为绝对路径,并且通过deps形式注入依赖。
可见,经过FIS3打包后,define函数中自动填入id,deps参数,即模块ID和模块依赖;引用js时,相对路径被替换为绝对路径。