# require-any **Repository Path**: tangfangtao/require-any ## Basic Information - **Project Name**: require-any - **Description**: 基于AMD规范(requirejs),实时加载任意coffee-script(cjsx)、react(jsx)等后现代的js近亲文件,实时编译(翻译),并将结果缓存在 HTML5 的 LocalStorage,并基于 AMD 机制进行加载。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 8 - **Created**: 2016-04-30 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # require-any 基于AMD(requirejs)机制,加载后现代的 javascript 近亲文件(如 coffee-script 、 react 、 emacscript6 等),实时编译(转换)为 js,并将结果缓存在 HTML5 的 localStorage,并基于 AMD 机制进行加载。 取名 **any** 包含了 anytime 和 anything 的含义。 核心的文件 `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](https://github.com/jsdf/coffee-react-transform),但很不幸的,这个类库的bower.json并没有配置可用于browser加载使用的独立版本,所以本类库的bower将这个文件作为main输出。 2. babel-transform,基于[babel-standalone](https://github.com/Daniel15/babel-standalone)。基于babel-standalone,目前实现对 emacscript6 、jsx 转换,emacscript6转换为全特性支持,包括import、module转换为amd、umd、commonjs等的支持,实际上现在已经实现了requirejs和[webpack](https://webpack.github.io/)(或[browserify](http://browserify.org/)) 下面这个是emacscript6的例子: ```es6 import hello from "any!./hello.coffee"; console.log(hello); let fun = () => console.log('hello e2s6') class Test { } module.exports = Test; ``` 他会转换出以下的javascript: ```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文件: ```javascript 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 ( ); } }); ``` 是不是很像我们做的npm文件?这个则会转换成这样的javascript: ```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` 文件 ```javascript 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` ```javascript 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.build` 为 `true` 的话,所有any前缀请求都会去掉相应的后缀文件名,即加载这个模块的js文件。如:test/hello.js。