美文网首页
使用FIS3解决seajs中模块的路径匹配问题

使用FIS3解决seajs中模块的路径匹配问题

作者: caiminghan | 来源:发表于2018-10-10 20:16 被阅读0次

    最近使用seajs开发的时候遇到一些问题,在此记录一下分享给大家。

    模块定义

    遵循seajs规范,模块化的js需要使用define函数定义,一个js文件即一个模块。define(id, deps, factory) 函数包括三个参数:iddeps、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.userequire 引用的是不具名模块(未定义了 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写为相对路径,而打包之后变为绝对路径。


    index.html.jpg

    下图为demo.js打包前后的对比,可以看到打包前模块ID和模块依赖未定义,require()函数中路径为相对路径。打包之后,模块ID被定义为文件的绝对路径,原文件中require函数中的资源ID也变为绝对路径,并且通过deps形式注入依赖。


    demo.js.jpg
    可见,经过FIS3打包后,define函数中自动填入id,deps参数,即模块ID和模块依赖;引用js时,相对路径被替换为绝对路径。

    相关文章

      网友评论

          本文标题:使用FIS3解决seajs中模块的路径匹配问题

          本文链接:https://www.haomeiwen.com/subject/gnruvftx.html