code: function readServices(services, configFilePath) {
      _lodash2.default.forEach(services, (init, serviceId) => {
        if (_lodash2.default.isPlainObject(metadata.services[serviceId])) return;
        // $Flow
        let serviceDir = init.dir;
        if (!serviceDir) {
          for (let d of mdirs) {
            serviceDir = _path2.default.join(d, serviceId);
            if ((0, _utils.isDirectory)(serviceDir)) {
              break;
            }
          }
        } else if (!_path2.default.isAbsolute(serviceDir)) {
          serviceDir = _path2.default.join(_path2.default.dirname(configFilePath), serviceDir);
        }
        if (!(0, _utils.isDirectory)(serviceDir)) {
          if (init.optional) {
            return;
          }
          throw new Error(`Service '${serviceId}' not found!`);
        }
        let cfg = _extends({
          id: serviceId,
          dir: serviceDir,
          config: ''
        }, readService(serviceDir, metadata.locales));
        metadata.services[serviceId] = cfg;
  
        let serviceConfigFile = _path2.default.join(serviceDir, 'config', serviceId + '.js');
        if ((0, _utils.isFile)(serviceConfigFile)) {
          cfg.config = serviceConfigFile;
          // $Flow
          let serviceConfig = require(serviceConfigFile).default;
          resolvePluginPath(serviceConfig, serviceConfigFile, mdirs);
          configs[serviceId] = serviceConfig;
          readServices(serviceConfig.services || {}, serviceConfigFile);
        } else {
          configs[serviceId] = {};
        }
      });
    }
docs: 递归遍历Service