转载

Git 项目推荐 | 基于 RequireJS 加载近亲文件

require-any

基于AMD(requirejs)机制,加载后现代的 javascript 近亲文件(如 coffee-script 、 react 、 ecmascript6 等),实时编译(转换)为 js,并将结果缓存在 HTML5 的 localStorage,并基于 AMD 机制进行加载。

取名 any 包含了 anytime 和 anything 的含义。

安装说明

目前分为3个分支:

  1. master分支,包含了require-any、transpiler-babel、transpiler-coffee
  2. babel分支,包含了require-any、transpiler-babel
  3. coffee分支,包含了require-any、transpiler-coffee

3个分支的源代码部分都是一样的,唯一的区别是bower.json中 maindependencies 的不同。

bower install https://git.oschina.net/janpoem/require-any.git // or 你只使用es6 bower install https://git.oschina.net/janpoem/require-any.git#babel // or 你只使用coffee bower install https://git.oschina.net/janpoem/require-any.git#coffee

已经register到bower了,可以直接:

bower install require-any // or 你只使用es6 bower install require-any#babel // or 你只使用coffee bower install require-any#coffee

核心的文件 require-any.js 实现如下内容:

  1. 基于AMD的方式指定加载资源(基于XHR),如 requirejs([any!test/Error.jsx])
  2. 实现了一个简单基于 HTML5 LocalStorage 的本地缓存的加载和比较的机制,用于对编译(翻译)完成的源代码(包含SourceMaps)进行缓存。
  3. 实现了一个简易的XHR加载器(用于加载源代码)。
  4. 一些辅助的基础函数。

本类库预设的实现了两个实时翻译器( XHR 加载,并将翻译结果缓存在 LocalStorage ):

  1. coffee-transform,基于 coffee-script 官方类库进行编译。同时支持 cjsx 格式(coffee-script的jsx),基于 coffee-react-transform ,但很不幸的,这个类库的bower.json并没有配置可用于browser加载使用的独立版本,所以本类库的bower将这个文件作为main输出。
  2. babel-transform,基于 babel-standalone 。基于babel-standalone,目前实现对 ecmascript6 、jsx 转换,ecmascript6转换为全特性支持,包括import、module转换为amd、umd、commonjs等的支持,实际上现在已经实现了requirejs和 webpack (或 browserify )

下面这个是ecmascript6的例子:

import hello from "any!./hello.coffee";  console.log(hello);  let fun = () => console.log('hello e2s6')  class Test {  }  module.exports = Test;

他会转换出以下的javascript:

define(["module", "any!./hello.coffee"], function (module, _hello) {   "use strict";    var _hello2 = _interopRequireDefault(_hello);    function _interopRequireDefault(obj) {     return obj && obj.__esModule ? obj : {       default: obj     };   }    function _classCallCheck(instance, Constructor) {     if (!(instance instanceof Constructor)) {       throw new TypeError("Cannot call a class as a function");     }   }    console.log(_hello2.default);    var fun = function fun() {     return console.log('hello es6');   };    var Test = function Test() {     _classCallCheck(this, Test);   };    module.exports = Test; });

而如下面的jsx文件:

var React = require('react');  module.exports = React.createClass({     displayName: 'Test',     getInitialState: function() {         return {             count: 0         }     },     click: function(event) {         this.setState({ count: this.state.count + 1 });     },     render: function () {         return (             <button onClick={this.click}>                 Test + {this.state.count}             </button>         );     } });

是不是很像我们做的npm文件?这个则会转换成这样的javascript:

define(['module', 'react'], function (module, React) {     'use strict';      module.exports = React.createClass({         displayName: 'Test',         getInitialState: function getInitialState() {             return {                 count: 0             };         },         click: function click(event) {             this.setState({ count: this.state.count + 1 });         },         render: function render() {             return React.createElement(                 'button',                 { onClick: this.click },                 'Test + ',                 this.state.count             );         }     }); });

基本处理流程

基本的流程:

  1. XHR发起请求源文件;
  2. XHR的 HEADERS_REVICES 阶段去检查 localStorage 是否有该文件的缓存。
    • 有缓存,比较源文件的最后更新时间(**Last-Modified**)和文件长度(**Content-Length**);
      • 相同,中断(abort)该次XHR,直接从缓存读取编译的结果;
      • 不相同,继续加载源文件,并编译,写入缓存;
    • 没有缓存,继续加载源文件,并编译,写入缓存;
  3. 用AMD机制加载编译的结果。

配置说明

可以参考 js/main.js 文件

var rjsConfig = {     //baseUrl: './js',     isDebug: true,     paths: {         'react': 'bower_components/react/react',         'react-dom': 'bower_components/react/react-dom',         'babel': 'bower_components/babel-standalone/babel',         'coffee-script': 'bower_components/coffee-script/extras/coffee-script',         'coffee-react-transform': 'src/coffee-react-transform',         // 指定加载的协议,你可以指定任意名称,比如load         'any': 'src/require-any',         // babel 转换器         'coffee-transform': 'src/coffee-transform',         // coffee-script 转换器         'babel-transform': 'src/babel-transform'     },     any: {         // 指定缓存存储的空间         cacheKey: 'my-cache',         // 是否编译模式,如果是编译模式,则直接加载这个模块的js文件         // any!test.jsx,当build = true,则会去加载 test.js 文件         build: false,         // 是否显示调试的信息         debug: true,         // 声明相关的,插件         plugins: {             coffee: 'coffee-transform',             es6: 'babel-transform'         },         // 后缀文件名的别名,指定用哪个插件来进行处理         ext: {             cjsx: 'coffee',             jsx: 'es6'         },         // 后缀转换(编译)时的参数,以后缀名为指向。         // 如果这里指定了jsx,则优先取jsx的配置。         // 如果没指定jsx,则会加载es6的配置。         options: {             es6: {                 plugins: ["transform-es2015-modules-amd"]             }         }     } }; rjsConfig.urlArgs = "version=" + (new Date()).valueOf(); requirejs.config(rjsConfig);

代码使用

可以参考 index.html

requirejs(['any!test/hello.coffee', 'any!test/Table.cjsx', 'react', 'react-dom', 'any!test/Test.jsx', 'any!test/Error.jsx'], function(hello, Table, React, ReactDOM, Test, Error) {     ReactDOM.render(React.createElement(Table), document.getElementById('test1'));     ReactDOM.render(React.createElement(Test), document.getElementById('test2')); });

上述中,如果 config.any.buildtrue 的话,所有any前缀请求都会去掉相应的后缀文件名,即加载这个模块的js文件。如:test/hello.js。

原文  http://git.oschina.net/janpoem/require-any
正文到此结束
Loading...