Jan Hančič 公布了一个在一次请求里同时加载 CSS 和 JavaScript 的方案,platypus.js。
实现原理是利用 CSS 的 content 属性,把 JavaScript 转换成 base64 字符串放进去,再动态插入 DOM。
示例 CSS:
#platypus-0 {
  display: none;
  content: 	'YWxlcnQoJ0hpLCBteSBmcmllbmQhIEZyb20gQ2hyaXMnKQo=';
}
示例 JS:
(function ( document ) {
  var linkTags = document.querySelectorAll ( 'link[rel="stylesheet"]' );
  for ( var i = 0; i < linkTags.length; i++ ) {
    var dummyDiv = document.createElement ( 'div' );
    dummyDiv.id = 'platypus-' + i;
    document.body.appendChild ( dummyDiv );
    var styles = document.defaultView.getComputedStyle ( dummyDiv, null );
    var js = styles.getPropertyValue ( 'content' ); // w3c
    //backgroundImage = someElement.currentStyle["background-image"]; //IE
    if ( js === '' ) {
      continue;
    }
    dummyDiv.parentNode.removeChild ( dummyDiv );
    if ( js[0] === "'" || js[0] === '"' ) {
      js = js.substr ( 1, js.length - 2 );
    }
    var scriptTag = document.createElement ( 'script' );
    // window.atob - decode base64 string, unavailable on IE9-, MDN says IE10 supports it
    scriptTag.innerHTML = atob ( js );
    document.body.appendChild ( scriptTag );
  };
} ( document ) );
按照 Jan 的说法,platypus.js 兼容非兼容视图的 IE9,大致上主流的桌面、移动浏览器都可以兼容。
这个方案很有意思,虽然 CSS 文件的大小增加了,但在越来越快的带宽和越来越好的 CDN 的影响下,DNS Lookup、Connecting 和 Wating 的消耗说不定比多出的部分少不了多少,特别是小文件。
我也想过利用 localStorage 来实现类似 manifest 的效果,简单的示例代码如下:
var load = (function() {
  var insertToDOM, getSource
  insertToDOM = function( content ) {
    var script = document.createElement( 'script' )
    script.textContent = content
    document.body.appendChild( script )
  }
  getSource = function( file ) {
    var source = localStorage.getItem( file )
    if (typeof source !== 'string') {
      // if no record, get source from server
      $.ajax( {
        url: file,
        success: function( data ) {
          localStorage.setItem( file, data )
          insertToDOM( data )
        }
      } )
    } else {
      insertToDOM( source )
    }
  }
  return function(files) {
    files.forEach( function( file ) {
      getSource( file )
    })
  };
})();
load( ['//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js',
  'script.js'] )
特点:
- 可以支持很多文件,理论上能用 Data URI 加载的都可以;
- localStorage的访问速度远远快于 DNS Lookup 等消耗;
- localStorage默认能支持最大 4MB 的储存,对于大部分站点完全足够;
- 把脚本封装成 (fn)()的形式并在底部插入特定的变量可判断版本、是否加载完成等,便于控制;
- 可控性和易用性高于 manifest,不需要配置服务器,需要清空时操作localStorage即可,而localStorage的存储持久性和manifest基本一样。
只不过,这种做法和 AMD、CommonJS 等规范不太合拍——至少我还没想到好做法——小团队项目开发似乎挺不错,暂时只是草稿性质的想法。