Giter Site home page Giter Site logo

cube's Introduction

Cube

logo

模块化你的前端代码,像node.js一样编写模块。

Cube管理着前端三种类型的资源:

  • script js/coffee/jsx/...
  • style css/stylus/less/...
  • template html/ejs/jade/...

Build Status NPM version

Install

npm install -g node-cube

安装完成之后,命令行增加一个命令 cube

clone本工程到本地

cd cube
cube start example

cube的样板工程就启动了,example中有cube支持的功能测试case 也是web页面侧的测试用例

Getting Start (6 steps)

  1. 初始化cube:

在node工程的root目录下,安装node-cube:

> npm install -D node-cube
  1. 在server中挂载cube middleware
const app = require('express')();
const Cube = require('node-cube');
let cubeM = Cube.middleware({
  root: path.join(__dirname, '../assets')
});
app.use('/assets', cubeM);

cubeM支持静态服务,所以设置完之后,整个assets目录即可被访问。

  1. 初始化前端html(通常在node后端模板中)
<!-- cube.js由cubeM中间件提供,是个虚拟文件,assets目录下没有,也无需有;cube build时会自动生成 -->
<script src='/assets/cube.js'></script>
<script>
  /** init cube, tell cube where to load modules */
  Cube.init({
    base: '/assets',
    debug: true,
    version: 12345
  });
  /** 
   * start loading main.js and run it
   * 下面的use方法将根据上面初始化设置的base作为根地址,加载所有依赖的文件
   *  '/main.js' 意味着访问到 assets/main.js
   */
  Cube.use('/main.js', function (App) {
    console.log(App.run({
      /** config object here */
    }));
  });
</script>
  1. 配置cube支持前端的各种脚本编译方式

cube有很多种配置方式,但是推荐使用如下方式:在assets/package.json中编写配置项

assets/package.json通常管理着前端的所有依赖,配置在cube段的config,在cube开发模式和cube build时都会来读取这份配置,配置在此可以保证build的时候和开发模式配置一致。

{
  "cube": {
    "moduleMap": {
      /**
       * 有些编译好的模块,可以通过映射来加速
       */
      "react": "dist/react.js",
      "modulemap": "lib/index.js"
    },
    "processors": {
      ".less": "cube-less",
      /**
       * 支持本地自定义processor, 其路径可以是相对路径(相对package.json的路径)
       * 也可以是绝对路径
       */
      ".tpl": "../custom_processor",
      /**
       * 支持配置process参数
       */
      ".jsx": [
        ["cube-babel", {}]
      ],
    }
  },
  ignoreRules: []
}

其中:

  • moduleMap 为一些已经build成single-file的模块提供filemap,以加速加载
  • processors 对象定义各种文件的处理器
  • ignoreRules 中定义build时的忽略规则,和.cubeignore功能类似
  • export 定义需要被导出的文件,补充自动识别导出文件的不足

ok, 到此cube初始化完毕,可以像编写node.js一样编写前端代码了。

  1. 编写前端代码
// main.js
var cookie = require('cookie');
var tpl = require('./test.html');

function  init() {
  // init layout
  $('body .main').html(tpl());
  // get nick
  var nick = cookie.get('nick');
  if (!nick) {
    nick = 'guest';
  }
  $('.node-nick').text(nick);
}
init();
// 异步加载css
load('../css/module.css', nameSpace); // namespace [optional]: prefix for css selector

ok,一个很简单的一个模块,index.html加载了main.js,便开始执行:设置头部用户登录昵称

Cube的模块加载是支持像node一样寻址node_modules目录的,在wwwroot目录下安装模块,可以被直接require使用, 所以可以把稳定的代码模块,发布到npm仓库实现代码复用

引用现有的包, 你只需要

  • 编写好package依赖
  • npm install 注意这里的npm install是安装在静态资源目录,不是工程根目录。
  • 像node一样引用这些模块

注意node_modules,虽然和node.js的模块一模一样使用,但是它们安装在不同的地方。 前端工程里使用到的模块,需要安装在静态资源目录下,如下结构:

/project
        /assets
              /node_modules   # client side node_modules
              /common
              /css
              - package.json  # 前端所依赖的模块声明
        /lib
        /controller
        /node_modules         # server side node_modules
        - package.json        # 后端所依赖的模块申明
  1. build代码, release成静态代码

完成开发之后,模块都会被预编译、压缩成一个个小文件,合并,然后发布到线上(cdn服务器、云存储 或 其他)

cube提供build命名来方便的完成这一任务

# build static folder
cube build $resource_path -o $resource_path.release --smart --mangle-file-name

cube build的参数:

    -h, --help             output usage information
    -o, --output [value]   set the output dir
    --output-file [value]  set the output file
    -b, --base [value]     the http base for resouce 
    -r, --root [value]     setup project base dir, the root
    --remote [value]       set the namespace for remote call
    --export [value]       files will be exported, do not merge, example: /a.js,/b.js
    --mangle-file-name     mangle the file name into random name
    --without-compress     do not compress code
    --without-wrap         do not wraper code
    --smart                smart build, only build necessary files

在静态资源目录下,编写 .cubeignore来排除不需要被处理的文件,格式和.gitignore类似:

[skip]
/node_modules/jquery/jquery.min.js
[ignore]
/node_modules/.bin
  • 匹配skip段的文件,将跳过编译,直接copy到目标目录
  • 匹配ignore段的文件,将直接忽略,build之后不会出现在目标目录中

不添加标记的时候,默认都为skip, 例如:

/test/

cube 在build的时候将直接copy文件,而不会build代码

.cubeignore 文件的寻址 会从build目录开始逐级往上寻找,直到找到为止

浏览器端API

/**
 * 开启debug模式, 会打印模块加载调试信息
 * @static
 */
Cube.debug();

/**
 * 初始化
 * @static
 * @param options {Object}
 *   charset {String} script标签
 *   base {String} 服务器端模块的http前缀地址
 *   debug {Boolean} 是否开启debug
 *   version {Number} 静态资源版本号,刷缓存用
 *   timeout {Number} 加载脚本超时时间
 *   remoteBase:{Object} 远程模块库映射
 */
Cube.init(options);

/**
 * 异步加载模块,带回调,页面的主入口一般就这个写法
 * @static
 * 注意module传入的寻址规则, 以下规则等效,都是基于 base 根目录下
 *    /app.js
 *    ./app.js
 *    app.js
 */
Cube.use(module, cb);
Cube.use([mod1, mod2], function(mod1, mod2) {
  // TODO: your code here
});

/**
 * 注册页面已通过script标签加载过的模块,避免重复加载
 * @static
 * 如下,注册 jquery, lodash
 * 注意后端assets目录下,请不要安装这些模块
 */
Cube.register('jquery', $);
Cube.register('lodash', _);
  • 注意 Cube.use 传入的参数寻址,基于当前 init的时候指定的base, 即跟目录下
Cube.use('/app.js', cb);
Cube.use('./app.js', cb);
Cube.use('app.js', cb);

以上是等效的,都引用了主类目下的 app.js 模块

  • cube支持remote源的模式
Cube.init({
  remoteBase:{
    test: 'http://test.com/assets'
  }
});

当test.com的assets发布的时候设置了cube build --remote=test, 模块都会被设置一个remote命名空间,这样的remoteBase只要命名空间不冲突,可以实现站点间模块共享。

服务器端API

服务器端cube提供两种模式: 1. middleware模式, 2. 独立初始化 3. 命令行工具

  • middlware 模式
const Cube = require('node-cube');
let cube = Cube.middleware(options);
  • 独立初始化
const Cube = require('node-cube');
let cube = new Cube(options);

配置对象 options
{
  /**
   * 静态资源的绝对路径, 工程前端代码的根目录
   * @type {String}
   */
  root: ''
  /**
   * 端口
   * @type {Number}
   */
  port: 8080,
  /**
   * 是否middleware模式
   * @type {Boolean}
   */
  middleware: true,
  /**
   * 所有资源文件(如css中图片)的http前缀路径,
   * 一般是一个站点的绝对路径`/`,或者`http://`完整路径
   * @type {String}
   */
  base: '/',
  /**
   * 编辑模式下,缓存目录,默认在 $root/.cubecache
   */
  cacheDir: '',
  /**
   * 浏览器端文件缓存时间,最终会应用到http头:Cache-Control: public, maxAge=xxx
   * @type {Number}
   */
  maxAge: 600
  /**
   * 配置文件的处理器 processors
   * 这个配置更推荐在 package.json的 cube 属性中配置,这样build和debug的时候同时生效
   * @type {Object}
   */
  processors: {
    '.jsx': [
      ['cube-react', {}],  // processor with config
      'minify'
    ],                     // multi-processor
    '.jsw': 'jsw'          // single processor
  },
  /**
   * 开发模式下是否开启缓存, 默认开启
   * @type {Boolean}
   */
  devCache: true,

  /**
   * optimize file load on dev mode, default is true
   * @type {Boolean}
   * 开启加上之后,dev模式下会
   */
  optimize: true,
  /**
   * 模块映射, 主要是加速加载用, 大部分的模块其实已经有构建好的 ./dest/$mod.js
   * {
   *    react: './dest/react.min.js'
   * }
   */
  moduleMap: {}
  /**
   * 忽略依赖解析,主要是配合前端的 Cube.register()用
   * 在前端页面已经加载的公共资源,可以通过设置服务端的这个ignore来实现共享
   */
  ignoreModule: {
    react: true
  }
}
  • cli模式
# 本地开发的时候启动服务,指定静态文件目录,即可服务起来
> cube start your_project_dir

# 初始化工程, 初始化一个简单的case
> cube init dir

# 打包发布工程
> cube build dir

配置优先级

构造函数传入 > package.json > cube内置配置

  • processors 优先级

    构造函数传入 > package.json中配置 > cube默认配置

  • ignoreRule 优先级

    ignoreRule的配置同等优先级,merge之后都会生效

    构造函数 = .cubeignore = package.json

Customize Cube Processors

一个典型的插件代码:

var path = require('path');
/**
 * 构造函数
 * @param {Cube} cube Cube instance
 */
function CustomProcessor(cube) {
	this.cube = cube;
}
CustomProcessor.type = 'style';
CustomProcessor.ext = ['.sass'];
CustomProcessor.prototype.process = function (data, options, callback) {
	/**
   * 在这个函数中处理data对象,data.code已经拿到了源文件,例如less的处理
   * 就是将data.code编译成css,然后重新赋值回data.code。
   *  data {Object} 
   *    queryPath
   *    realPath
   *    code
   *    source
   */
	callback(null, data);
};
module.exports = CustomProcessor;

可参考目前已有的processor源码,来更快的理解自定义processor。

cube's People

Contributors

a8397550 avatar albin3 avatar alsotang avatar cctv1005s avatar cwtuan avatar elvira1112 avatar ericdum avatar fishbar avatar hqidea avatar lenzhang avatar tinysymphony 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cube's Issues

彻底的插件化

将现有语言的支持拆解出来,变成独立的node_module,方便用户自定义。
在开发和编译过程,都将带来一些方便

cube build error: lodash

lodash模块 : lodash/fp/valueOf.js

会提示模块找不到,而valueOf.js的代码非常简单

module.exports = require('./wraperValue');

代码合并 - 半自动

分析出整个工程的结构,自动合并一些代码, 并支持人工干预,使最终结果更准确

cube支持相对路径

base 的配置, 支持为空时,相对当前页面路径寻址文件

Cube.init({
  main: '/test.js'
  base: ''
})

细节优化

  • node_modules 目录编译时,减少无关代码copy
  • less 编译出错时,更友好的提示信息
  • 原生模块加载时不要出现 ‘/assets${module_name}’ 这种无谓的寻址

require(module) 参数支持变量

支持类似形式的路径分析

require('./' + variable + '.jade');
require('./path_' + variable + '/config.js');

部分支持类似形式的路径分析

async(variable + '.jade');    // 默认variable在最前的情况,为绝对路径,不做相对路径计算,只改变后缀
async(variable); // 默认为全局变量,  考虑是否嵌套方法处理变量

__filename

是否能去掉__filename, 如果引用数据,数据为对象格式,经常会报错

编译--remote问题

viewport.js 进行第一层引用

Grid = require 'DBU_REMOTE:/com/grid/index.js'

第一层grid/index.js 在去引用第二层grid/index.jade.js

Cube("DBU_REMOTE:/com/grid/index.js",["DBU_REMOTE:/com/grid/index.jade.js"]

第二层grid/index.jade.js在编译的时候,应该也要加上DBU_REMOTE:/才对

Cube("/com/grid/index.jade.js",["jade_runtime"]

后端忽略强制解析buildInModule

后端忽略强制解析buildInModule, 抛出warning, 但不打断请求, 模块继续输出
寻址失败的错误在模块依赖加载时触发。

css 文件的 url()转换

打包时对 css 文件中 url(...)进行了转换,即使配置了 skip、ignore 还是没有跳过
需要增加配置运行跳过这个步骤,css 原文输出

路径回归

--XX
  | --d-chart
      |-- src
           |--util
                |-- index(用underscore,找不到)
      |-- node_module
          |-- underscore (没有了)
--underscore(理应找这里)

support remotebase

服务端变更

  • 更改build的wraper: Cube(moduleName, [require], callback, namespace), 只影响到build环节
  • process_js 解析require中的路径 require("remote:/asdfad")
  • 引用远端脚本的文件,编译之后Cube(moduleName, [['remote', path]], callback, namespace)

客户端runtime的更改

wraper函数更新,支持namespace参数,但保持和requireJS的风格兼容

Cube(moduleName, [a, b, c], callback, namespace);

初始化增加 remoteBase 选项,该选项为Object,支持多源

Cube.init({
   ....
   remoteBase: {
     'remoteAlias': 'http://remote_real_path'
   }
   ....
});

把执行顺序反过来

将模块的执行顺序由叶子模块->根模块修改为根模块->叶子模块

好处:无需解循环引用的问题,发生循环引用时按node的逻辑处理

支持glslify等类似模块的加载

glslify等模块带有后端代码,如:
2017-02-24 4 45 31

希望有个类似于Browserify的Browserify Transform, 如下:
2017-02-24 4 45 46

或者类似Webpack的glslify-loader module。
😀

关于前端require

cube 前端会执行函数内部并不执行的require,造成一些库不能运行

一个异常

testcode:

Cube.use('a.js', function (a) {
   Cube.use('a.js', function () {
       // TODO something
   });
});

循环引用的问题

循环引用解法

循环引用在前端的依赖中,必须断开链路。 什么时候断开合适,看看下面的两种场景。

场景一,起始文件弱依赖

a.js

module.exports = function () {
   var b = requrie('./b');
}

b.js

var a = require('./a');
module.exports = function () {
  a.hello();
};

场景二,末尾文件弱依赖

a.js

var b = requrie('./b');
module.exports = function () {
   b();
}

b.js

module.exports = function () {
  require('./a').hello();
};

.cubecache的清理问题

当出现极端情况的异常时,.cubecache中的代码需要被清理,需要提供一个便捷的方式。

目前设想的方案,在页面上提供一个浮动小图标,点击清理并刷新页面

入口文件自动修复路径问题

通常情况需要传入的模块是绝对路径开头

cube.use('/test/fish.js');

这在编译出来的模块中没问题,因为编译之后的地址都是绝对地址,但是在页面的初始配置中就容易忽略,加入容错机制

cube.use('test/fish.js');  // 兼容此种场景
cube.use('./test/fish.js'); // 兼容更规范的场景

在html页面上部署cube时, Cube.use 的场景, 可以解释为 pwd = Cube.base

前端打包压缩

希望增加前端js打包合并压缩的功能 并可以有是否uglify、css的压缩策略等压缩选项。

v3.0.0-beta.1

  • mock process、global, 兼容前后端一体的模块
  • build时模块智能合并,并清理require,压缩体积
  • 完善的文档,结构、用法、接口说明
  • 支持需要运行时做browserify进行转换的模块

css内资源依赖问题

需要将css中的资源地址转为绝对地址, 比如:

.btn_close {
  background: url(./icon_close.png)
}

转为

.btn_close {
  background: url(/img/icon_close.png) /* abs path */
}

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.