Giter Club home page Giter Club logo

mod's Introduction

#modJS

简介

modJS是一套的前端模块加载解决方案。与传统的模块加载相比,modJS会根据产品实际使用场景,自动选择一种相应的方案,使最终的实现非常轻量简洁。

使用

模块的定义

  • modJS是一个精简版的AMD/CMD规范,并不完全遵守AMD/CMD规范,目的在于希望给使用者提供一个类似nodeJS一样的开发体验,同时具备很好的线上性能。

使用define来定义一个模块:

define (id, factory)

在平常开发中,我们只需写factory中的代码即可,无需手动定义模块。发布工具会自动将模块代码嵌入factory的闭包里。

factory提供了3个参数:require, exports, module,用于模块的引用和导出。

  • modJS的发布工具会保证你的程序在使用之前,所有依赖的模块都已加载。因此当我们需要一个模块时,只需提供一个模块名即可获取:

require (id)

和NodeJS里获取模块的方式一样,非常简单。

因为所需的模块都已预先加载,因此require可以立即返回该模块。

  • 考虑到有些模块无需在启动时载入,因此modJS提供了可以在运行时异步加载模块的接口:

require.async (names, onload, onerror)

names可以是一个模块名,或者是数组形式的模块名列表。

当所有都加载都完成时,onload被调用,names对应的所有模块实例将作为参数传入。

如果加载错误或者网络超时,onerror将被触发。

超时时间可以通过require.timeout设置,默认为5000(ms)。

使用require.async获取的模块不会被发布工具安排在预加载中,因此在完成回调之前require将会抛出模块未定义错误。

require.loadJs (url)

异步加载脚本文件,不做任何回调

require.loadCss ({url: cssfile})

异步加载CSS文件,并添加到页面

require.loadCss ({content: csstext})

创建一个样式列表并将css内容写入

##说明

modJS只实现了AMD的一个子集,如果需要使用完整兼容AMD规范的版本,请使用amd目录下的esl-mod.js,这个版本是基于esl版本基础之上实现了fis的需求。

相关项目

自动化框架:fis

自动添加define插件:fis-postprocessor-jswrapper

mod's People

Contributors

2betop avatar fouber avatar hefangshi avatar oxund avatar waltershen avatar wangcheng714 avatar zhangtao07 avatar zjcqoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mod's Issues

useSameNameRequire=true时会提前加载require.async声明的模块样式

fis-config.js

fis.match('/node_modules/**.js', {
    isMod: true,
    useSameNameRequire: true
});

fis.match('/components/**.js', {
    isMod: true,
    useSameNameRequire: true
});

fis.match('/page/**', {
    isMod: true,
    useSameNameRequire: true
});

业务逻辑:

if(false){
        require.async('app/header-download/header-download'); 
    }

结果页面按预期的没有加载app/header-download/header-download.js,
却会预先加载'app/header-download/header-download.css'

Cannot find module `src/assets/js/index`

FIS3 release 完后

dist/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Hello</title>
  <script src="/static/mod.js"></script>
</head>
<body>
  <div id="app"></div>
  <script>
    require('src/assets/js/index');
  </script>
</body>
</html>
dist/src/assets/js/index.js

define('src/assets/js/index', function(require, exports, module) {

  'use strict';

  var hello = 'hello';

  alert(hello);

});

目录似乎是对的,但是打开浏览器后报 mod.js:108 Uncaught [ModJS] Cannot find module 'src/assets/js/index'

fis-conf.js 很简单

fis.match('/src/**/*.js', {
  parser: fis.plugin('babel-5.x', {
    optional: ["es7.decorators", "es7.classProperties"]
  }),
  rExt: '.js'
});

fis.hook('commonjs');

fis.hook('node_modules');

fis.match('/src/**/*.js', {
  isMod: true
})

require 和 require.async 无法加载 jquery 、underscore 这些模块

如题,require 加载 jquery 这些出现

modjs_jquery

html源代码如下

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="/Public/Js/Lib/mod.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
     require('jquery');
</script>
</html>

运行的html源代码如下

  <!DOCTYPE html>
  <html>
  <head>
  <meta charset="UTF-8">
  <title></title>
  </head>
  <body>
  <script type="text/javascript" charset="utf-8" src="http://localhost:8080/test/Public/Js/Lib/mod.js"></script>
  <script type="text/javascript" charset="utf-8" src="http://localhost:8080/test/Public/Js/Lib/jquery.js"></script>
  <script type="text/javascript">
       require('jquery');
  </script>
  </body>
  </html>

modjs_net

用 require.async 加载的话 jquery 文件是加载了,但是回调没有反应,运行代码如下

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script type="text/javascript" charset="utf-8" src="http://localhost:8080/test/Public/Js/Lib/mod.js"></script>
<script type="text/javascript" >
require.resourceMap({"res":{"jquery":{"url":"http://localhost:8080/test/Public/Js/Lib/jquery.js"}},"pkg":{}});
</script>
<script type="text/javascript">
     require.async('jquery',function($){
         console.log('加载成功');
     });
</script>
</body>
</html>

id.replace is not a function

id = "node_modules/object-assign/index", factory = function (require, exports, module...

Uncaught TypeError: id.replace is not a function

有没有计划添加类似 requirejs 的 shim 机制

requirejs 有 shim 的机制,能够使用一个非模块化的文件

requirejs.config({
    //Remember: only use shim config for non-AMD scripts,
    //scripts that do not already call define(). The shim
    //config will not work correctly if used on AMD scripts,
    //in particular, the exports and init config will not
    //be triggered, and the deps config will be confusing
    //for those cases.
    shim: {
        'backbone': {
            //These script dependencies should be loaded before loading
            //backbone.js
            deps: ['underscore', 'jquery'],
            //Once loaded, use the global 'Backbone' as the
            //module value.
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                //Using a function allows you to call noConflict for
                //libraries that support it, and do other cleanup.
                //However, plugins for those libraries may still want
                //a global. "this" for the function will be the global
                //object. The dependencies will be passed in as
                //function arguments. If this function returns a value,
                //then that value is used as the module export value
                //instead of the object found via the 'exports' string.
                //Note: jQuery registers as an AMD module via define(),
                //so this will not work for jQuery. See notes section
                //below for an approach for jQuery.
                return this.Foo.noConflict();
            }
        }
    }
});

mod 有计划添加这个支持吗?

mod.js 出现某一个id没有找到的情况

具体情况是自己用nginx搭了一个本地环境,跑起来之后报错,代码 throw '[ModJS] Cannot find module ' + id + ''; 切到浏览器里去看network选项没有加载该id对应的js文件,请问这是什么原因导致的?

onload && onload.apply 类似的检验不严谨导致使用不便的问题

示例:

function getXXX (callback) {
    require.async('xxx', callback)
}

// 预加载
// 这样的使用方式,会导致传递给 require.async 的callback 会是 jq的event对象
// 因为modJS内部的判断 onload && onload.apply... 不够严谨进而导致报错
$(window).on('load', getXXX)    

// 主动加载
$('#showXXX').on('click', function(e){
    getXXX(function(xxx){
        xxx.show()
    })
})

我不得已给getXXX加上了参数校验:

function getXXX (callback) {
    if (typeof callback !== 'function') callback = function () {};

    require.async('xxx', callback)
}

表示看不懂test里面的例子,看了好几天

刚入行没多久,看到一个前辈使用的modjs这个工具,然后想学习一下,发现他使用的方式和网上使用的方式有很大的不同,然后现在我两种方法都没有出现效果

它使用的方式是这样的:
define('modules/jquery/jquery-2.2.4.min', function(require, exports, module) {
然后这里面就跟着框架或插件的源码,也没有导出啥的,require, exports, module这三个参数也没有用到
});

页面引用:

<script src="__TMPL__Public/movies/js/mod.js"></script> <script type="text/javascript" src="__TMPL__Public/movies/modules/jquery/tool.js"></script> <script type="text/javascript" src="__TMPL__Public/movies/modules/jquery/jquery-2.2.4.min.js"></script> <script type="text/javascript" src="__TMPL__Public/movies/modules/jquery/jquery.tap.js"></script> <script type="text/javascript" src="__TMPL__Public/movies/modules/jquery/pinchzoom.js"></script> <script type="text/javascript" src="__TMPL__Public/movies/modules/jquery/ajaxForm.js"></script> <script> //模块化 window.$ = window.jQuery = require('modules/jquery/jquery-2.2.4.min'); require('modules/jquery/jquery.tap'); require('modules/jquery/pinchzoom'); require('modules/jquery/tool'); require('modules/jquery/ajaxForm'); </script>

就是这样了,看着网上提供的例子,然后又看着他写的,就一脸的懵逼了

mod.exports = true

136行的判断有问题,ios8.4Safari有种情况mod.exports = trueObject.isExtensible方法报错

modjs经过fis3包裹后,里面的js代码不执行!?

使用fis3+art-template+bootstrap+jquery集成了一个后台框架。页面请求大部分是用接口;但是没有完全分离,页面是jsp渲染的,页面中有部分权限和变量要用jsp的变量!产出的前端代码必须放在tomcat里面运行。
1、modjs、jquery.js共用的就合并到一个没有包裹define的js中,直接在开始引入,暴露到全局中;
2、使用art-template,模板,拼接一个个页面,每个页面有自己的css和js,其中不执行的js,被isMod之后如下:

define('src/pages/sys/resource/index', function(require, exports, module) {
  'use strict';
  var _index = require('src/api/index');
  var API = _interopRequireWildcard(_index);
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
  
  var request = require('src/utils/request');
  
  $(function () {
    API.getSysResourceList(1, 15, function (data) {
      console.log(data);
    });
    window.alert('这是resource页面');
    console.log('sfsgsg');
  });
  //# sourceMappingURL=/static/map/pages/sys/resource/index.js.map
});
<!-- 加入布局 -->
{{extend '../../../layout/default/default.tpl'}}
<!-- 添加自定义标题 -->
{{block 'title'}}  admin {{/block}}
<!-- 添加页面自己的样式和脚本 -->
{{block 'head'}}
  <!-- 公共部分css -->
  <link rel="stylesheet" href="../../../assets/common/common.scss">
  <link rel="stylesheet" href="./index.scss">
{{/block}}
<!-- body主体显示区 -->
{{block 'main'}}
  <p class="admin">我是adminsfsf</p>${basePath}
{{/block}}
<!-- body后脚本文件after -->
{{block 'after'}} 
  <!-- 公共部分js -->
  <script src="../../../assets/common/common.js"></script>
  <script src="./index.js"></script>
{{/block}}

目前遇到问题是index.js包裹的define下的js不执行!!(不包裹define可以执行),请问问题出在哪?是哪里配置有问题么?

require.async 加载动态变量模块

require.async(moduleId, callback);
当moduleId为一个变量从hash获取,而非固定字符串比如"xxx"的时候,fis-postpackager-loader无法生成映射表,这个时候会加载模块失败。

原本想在页面自己输出RESOURCE_MAP,不依赖fis-postpackager-loader,但是map中文件的key为完整路径,并非moduleId。这个表就没法使用了,我fis的配置如下:

fis.match('js/page/(**).js', {
    isMod: true,
    moduleId: '$1'
});

请问有何办法?

Mod支持IE8及以下浏览器吗?

在windowXP系统下的IE8浏览器测试,会报136行错。

if (mod.exports && !mod.exports['default'] && Object.defineProperty && Object.isExtensible(mod.exports)) {
Object.defineProperty(mod.exports, 'default', {
value: mod.exports
});
Object.defineProperty(mod.exports, '__esModule', {
value: true
});
}

所以想问一下,是我的环境或者使用方法有问题,还是mod本身就不支持。谢谢

如何用另一名称替换require

如何替换mod默认的require方法,

试过(function(){
var require ,define;
.......
window.loadResources = require
})()

用自定义的名字替换mod里面的require,都不行

mod.js支持ie8浏览器的模块化加载么?

最近的项目在ie8下跑的时候,经常会出现:对象不支持此属性或方法
使用调试工具监视,var render = require(),(module.exports导出)的方法名的时候,有时候里面监视的方法能看到导出的方法,有时候不能,只显示.bind(that)。
能提示一下,在ie8浏览器下,编码要注意的细节么?

使用mod异步加载文件,失败后没有任何提示

使用modjs异步加载文件:
欲加载的文件列表:['template', '$']
其中jquery在没有使用define包裹的情况下,mod也能正常把jquery文件插入到dom节点中,但问题是此时的callback是没有运行的,也没有任何报错提示
仅仅是因为代码中if (0 == needNum--)值不相同,是jquery没有使用mod的define函数导致,
在此种情况下建议mod进行一个判断,至少给一个console报错提示,
此时不是异步加载的文件没有加载完毕,而是因为加载的文件不符合define包裹条件而没有执行正常callback。
这对于代码调试来说很有必要!!!

配置
fis.hook('commonjs', {
  paths: {
    $: 'static/lib/jquery.min.js'
  }
});
...

//异步加载
require(['template', '$'], function(template, jq){
        console.log(template({'name': 'abc'}));
        console.log(jq);
}, function(err){
        console.log(arguments);
});

script.onerror的支持

在IE6,7,8和opera中,script.onerror这个事件注册是不会触发的,这就导致如果调用loadScript传入onerror的时候在各浏览器下反应不一致,在上述浏览器中,只有在超时时才会触发,而在支持该事件的浏览器中,直接触发?

fis3+mod在mac下有问题

在mac下 require.async 一个js文件后,fis3编译出来的并没有这个js文件,而且引用到了同文件夹下同文件名的html文件并且去掉了后缀名。

mod.js加载页面依赖文件报错

使用mod.js加载页面脚本依赖时经常出现这样的报错问题,脚本文件是没问题的。出现报错之后再次刷新浏览器即可解决。这个是我的fis配置问题还是?求指教。。。
issue1

issue2

在mod.js基础上, 实现本地 localStorage 缓存

使用 mod.js, 配合 fis-postpackager-loader 生成 resourcemap, 然后在 mod.js 基础上, 实现将代码缓存在本地 localStorage, 当有新的发布时, 会将本地缓存的内容进行覆盖.

  1. mod.js初始化时, 会将本地过期的模块删除
  2. 调用 require.resourceMap 时, 会将本地没过期, 但是在resourceMap中不存在的模块删除
  3. define时, 会将模块缓存至本地

如果不想使用缓存, 可以在构建时, 使用 fis-plugin-uglifyjs的 global_defs, 设置 __MOD_CAHCE, 将缓存部分代码去除

diff --git a/mod.js b/mod.js
index d5adf29..d52b4fb 100644
--- a/mod.js
+++ b/mod.js
@@ -25,6 +25,128 @@ var define;
     var resMap = {};
     var pkgMap = {};

+    if(typeof __MOD_CACHE !== 'undefined' && __MOD_CACHE){
+        var cacheMap = {};
+        var cacheTime = 1000 * 60 * 60 * 24 * 10;
+        var supportCacheModule = !!(typeof(JSON) != "undefined" && window.localStorage);
+        var getModuleKey = function(id){
+            return '_m_' + id;
+        };
+        var getModuleUrl = function(id){
+            //
+            // resource map query
+            //
+            var res = resMap[id] || resMap[id + '.js'] || {};
+            var pkg = res.pkg;
+            var url;
+
+            if (pkg) {
+                url = pkgMap[pkg].url || pkgMap[pkg].uri;
+            }else {
+                url = res.url || res.uri || id;
+            }
+            return url;
+        };
+        var hasCacheModule = function(id){
+            if(cacheMap[id] && cacheMap[id].url == getModuleUrl(id)){
+                return true;
+            }else{
+                return false;
+            }
+        };
+        var hasValueModule = function(id){
+            return resMap[id] || resMap[id + '.js'] || false;
+        };
+        var useCacheModules = function(queues){
+            if(!supportCacheModule){
+                return queues;
+            }
+
+            var needLoad = [];
+            var docFrag = document.createDocumentFragment();
+
+            for(var i = 0; i < queues.length; i++){
+                var queue = queues[i];
+                var id = queue.id;
+                if(!hasCacheModule(id)){
+                    needLoad.push(queue);
+                    deleteCacheModule(id);
+                    continue;
+                }
+                var scriptNode = document.createElement('script');
+                scriptNode.setAttribute('type', 'text/javascript');
+                scriptNode.setAttribute('data-module', id);
+                try{
+                    scriptNode.appendChild(document.createTextNode("define('" + id + "', " + cacheMap[id].factory + ");"));
+                }catch(e){
+                    scriptNode.text = "define('" + id + "', " + cacheMap[id].factory + ");";
+                }
+                docFrag.appendChild(scriptNode);
+            }
+
+            head.appendChild(docFrag);
+
+            return needLoad;
+        };
+        var _writeCacheModule = function(key, module){
+            window.localStorage.removeItem(key);
+            window.localStorage.setItem(key, JSON.stringify(module));
+        };
+        var writeCacheModule = function(id, module){
+            if(!supportCacheModule){
+                return false;
+            }
+            var key = getModuleKey(id);
+            module.expires = (+new Date()) + cacheTime;
+            try{
+                _writeCacheModule(key, module);
+            }catch(e){}
+        };
+        var _deleteCacheModule = function(key){
+            window.localStorage.removeItem(key);
+        }
+        var deleteCacheModule = function(id){
+            if(!supportCacheModule){
+                return false;
+            }
+            var key = getModuleKey(id);
+            try{
+                _deleteCacheModule(key);
+            }catch(e){}
+        };
+        var cleanCacheModules = function(){
+            for(var id in cacheMap){
+                if(hasValueModule(id)){
+                    continue;
+                }
+                deleteCacheModule(id);
+            }
+        };
+        (function loadCacheModules(){
+            if(!supportCacheModule){
+                return false;
+            }
+            for(var key in window.localStorage){
+                if(!/^_m_/.test(key)){
+                    continue;
+                }
+                var module = JSON.parse(window.localStorage.getItem(key));
+                var id = key.substr(3);
+
+                // cache expire
+                if(module.expires < (+new Date())){
+                    window.localStorage.removeItem(key);
+                    continue;
+                }
+
+                cacheMap[id] = module;
+
+                // update cacheTime, and write back to localStorage
+                writeCacheModule(id, module);
+            }
+        })();
+    }
+
     var createScripts = function(queues, onerror){

         var docFrag = document.createDocumentFragment();
@@ -103,6 +225,13 @@ var define;
             });
         }

+        if(typeof __MOD_CACHE !== 'undefined' && __MOD_CACHE){
+            queues = useCacheModules(queues);
+            if(!queues || !queues.length){
+                return;
+            }
+        }
+
         createScripts(queues, onerror);
     };

@@ -117,6 +246,19 @@ var define;
             }
             delete loadingMap[id];
         }
+
+        if(typeof __MOD_CACHE !== 'undefined' && __MOD_CACHE){
+            // 缓存已经有了, 不需要再次覆盖写入
+            if(hasCacheModule(id)){
+                return;
+            }
+
+            // 写入缓存
+            writeCacheModule(id, {
+                url: getModuleUrl(id),
+                factory: factory.toString()
+            });
+        }
     };

     require = function (id) {
@@ -234,6 +376,10 @@ var define;
                 pkgMap[k] = col[k];
             }
         }
+
+        if(typeof __MOD_CACHE !== 'undefined' && __MOD_CACHE){
+            cleanCacheModules();
+        }
     };

     require.loadJs = function (url) {

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.