Skip to content

Latest commit

 

History

History
115 lines (93 loc) · 3.93 KB

05.md

File metadata and controls

115 lines (93 loc) · 3.93 KB

量身打造angular开发解决方案(5) - 生态模块

模块生态及版本管理是一个细思恐极的问题。

1. 为何不直接用bower

当前社区的模块质量良莠不齐,很多类库都不符合bower.json-spec,的规范,仓库里面经常有很多源码垃圾文件,甚至很多模块安装之后不可用或者根本安装不上。

@fouber 也曾多次提到「模块生态及版本管理是一个细思恐极的问题」, 所以scrat选择的方案是**「自建高质量的小范围生态」**。 对于社区的生态模块, 采用travis同步方式, 参见transform.js

不过作为angular的拥护者, 丢弃bower总是觉得可惜, 同时发现angular的周边模块质量相对好一点。

于是经过多次的反复纠结,于是编写了该组件,可以较完美的满足我的需求。

2. 解决思路

  • 简单的说,scrat是把模块转换的过程放到travis,而本方案是放到install过程。
  • 调用bower programmatic api安装依赖
//读取项目的组件配置文件(bower.json)
var projectMeta = getProjectMeta(root, directory);

//合并内置规则
projectMeta.overrides = _.defaults(projectMeta.overrides || {}, require('./bower-meta'));

//调用bower安装生态模块到component_modules
var installer = bower.commands.install(repo, {save: true}, {directory: 'component_modules'});

//安装完成后,清洗文件
installer.on("end", function (installed) {
  for(var key in installed) {
    var meta = _.assign(item.pkgMeta, projectMeta.overrides && projectMeta.overrides[componentName]);
    syncFiles(key, meta, componentRoot, ignore);
  }
});
  • 根据mapping配置,使用glob规则来清洗目录文件
//清洗文件(仅展示核心代码)
function syncFiles(componentName, meta, componentRoot, ignore){
  //...
  var srcDir = path.join(componentRoot, componentName);
  var targetDir = path.join(componentRoot, '.' + meta.name);

  //遍历所有mapping规则
  meta.mapping.forEach(function (pattern) {
    //匹配glob规则, 获取文件列表
    var files = globby.sync(pattern.src, {cwd: path.join(srcDir, pattern.cwd)});
    //复制文件到临时目录
    files.forEach(function (file) {
      var sourceFile = path.join(pattern.cwd, file).replace(/\\/g,'/');
      var targetFile = file.replace(/\\/g,'/');
      if (fs.statSync(path.join(srcDir, sourceFile)).isFile()) {
        console.log('    copy %s -> %s', sourceFile, targetFile);
        fs.copySync(path.join(srcDir, sourceFile), path.join(targetDir, targetFile));
      }
    });
  });

  //...
  //重写生态模块的元数据(bower.json)

  //替换临时目录为源码目录
  fs.removeSync(srcDir);
  fs.renameSync(targetDir, srcDir);
}

3. 封装方案

然后,我们把它独立为一个单独的插件, 复用出去: https://github.com/ng-workflow/ngfis-command-install

ngfis里面,npm install ngfis-command-install,再执行ngfis install则自动会找到该插件。

相关介绍参见: 「FIS插件扩展点列表」

4. 示例

{
  "name": "ngfis-showcase",
  "private": true,
  "dependencies": {
    "angular": "~1.3.7",
    "bootstrap": "~3.3.1",
    "zepto": "~1.1.6"
  },
  "devDependencies": {
    "angular-mocks": "~1.3.7"
  },
  "ignoreDependencies": [
    "jquery"
  ],
  "overrides": {
    "bootstrap": {
      "main": "css/bootstrap.css",
      "mapping": [{
        "cwd": "dist",
        "src": [
          "css/**.css",
          "!js/bootstrap.js",
          "fonts/**",
          "!**/*.min.*",
          "!**/*theme.*"
        ]
      }]
    }
  }
}

运行效果: snapshot