我的脚本加载器require

编写原因:

虽然现在mvvm框架大行其道,但是实际工作中公司还是有很多老项目需要维护,庞大重复的公共脚本引用,人为的增加了不必要的时间浪费,也不利于这些公共脚本文件的维护

设想:在一个common.js文件中维护所有的公共脚本,让所有公共脚本的相对地址都从这个common.js出发来达到每次引用公共脚本不需要逐一改变公共脚本的相对路径即只需维护common.js;

参考require.js 决定编写简化符合上诉功能的myrequire.js

页面示例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>我的模块加载器</title>
</head>
<body>
我的模块加载器
将所有脚本文件的引用简化为下面一条,data-main 为当前页面私有的js脚本文件
<script src="./js/myrequire.js" data-main="./js/index.js"></script>
</body>
</html>

  myrequire.js

(function(){
  try {//页面加载完成时获取当前页面的私有js地址,并获取其所在路径作为起始路径并保存在require.config中
    let script=document.getElementsByTagName('script');
    let baseUrl=curUrl=[].slice.call(script,0).filter(item=>{return item.getAttribute('data-main')})[0].getAttribute('data-main');
    let index=curUrl.lastIndexOf('/');
    if(index>-1){
      baseUrl=curUrl.slice(0,index+1)
    }
    require.config={curUrl,baseUrl};
  }catch (e) {
    throw new Error('入口script文件需要配置data-main属性');
  }
  function ajax(url){//加载对应的js脚本
    return new Promise(function(resolve){
      let script=document.createElement('script');
      script.src=url;
      resolve(script)
    })
  }
  function require(module){
   return ajax(resolvePath(module))
  }
  function resolvePath(url){//拼合路由地址,将以js文件为起点的其它脚本文件,转化成以html为起点的可被游览器识别的真实地址
    if(url.indexOf('http')==0||url.indexOf('/')==0){
      return url;
    }
    url= require.config.baseUrl+url;
    let urlarr=url.split('/');
    let nowUrl='';
    for(let i=0;i<urlarr.length;i++){
      switch (urlarr[i]) {
        case '.':
          break
        case '..':
          let lasetIndex=nowUrl.lastIndexOf('/');
          let lastSecondIndex=nowUrl.lastIndexOf('/',lasetIndex-1);
          if(lastSecondIndex>-1&&nowUrl!='../'&&nowUrl!='./'){//排除../,./
            nowUrl=nowUrl.slice(0,lastSecondIndex+1)
          }else{
            if(lasetIndex>-1){
              nowUrl='';
            }else{
              nowUrl+='../';
            }

          }
          break;
        default:
          if(i+1>=urlarr.length){
            nowUrl+=urlarr[i];
          }else{
            nowUrl+=(urlarr[i]+'/')
          }
      }
    }
    return nowUrl;
  }
  function addScript(script){//添加脚本文件
    let head=document.getElementsByTagName('head')[0];
    return new Promise((resolve => {
        head.append(script);
        script.onload=function(){
          resolve('ok')
        }
    }))

  }

  ajax(require.config.curUrl).then(script=>{
    addScript(script);
  });
  require.define=function(module,callback){//更改起始路由地址,将起点地址从index.js转成common.js所在路径,
    return require(module).then(async function(script){
      let index=module.lastIndexOf('/');
      if(index>-1){
        module=module.slice(0,index+1)
      }
      require.config.baseUrl=resolvePath(module);
      Promise.all([addScript(script)]).then(async function(res){
        let info =await loadPlug()//common中所有脚本文件加载完成后执行私有js,index.js的内容
        Promise.all(info.map(item=>{return addScript(item)})).then(res=>{
          callback()
        })

      })
    })
  }
  window.require=require;
})()

尝试一下

如公共文件pluga,plugb,jquery

//common/pluga.js
function a(){
  console.log('我是common中的a')
}
//common/plugb.js
function b(){
  console.log('我是common中的b')
  console.log($('body'))
}

维护公共js文件common/common.js

//common/common.js
async function loadPlug(){
  let plugs=[
    require('https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js'),
    require('pluga.js'),
    require('plugb.js'),
  ]
  return Promise.all(plugs)
}

私有js,index.js

require.define('../common/common.js',function (){
  b();
  a();
})

运行结果

 

 

 

 完美达到预期目的

posted @ 2021-12-17 11:02  *朝晖  阅读(76)  评论(0编辑  收藏  举报