require.js

  1. /**
  2. * 用来加载 fis 插件。通过它来加载插件,会优先从本地安装的 node_modules 目录里面找,然后才是 global
  3. * 全局安装的 node_modules 里面找。
  4. *
  5. * @function require
  6. * @param {String} paths... 去掉 fis 前缀的包名字,可以以多个参数传进来,多个参数会自动通过 `-` 符号连接起来。
  7. * @memberOf fis
  8. * @example
  9. * // 查找顺序
  10. * // local: fis3-parser-sass
  11. * // local: fis-parser-sass
  12. * // global: fis3-parser-sass
  13. * // global: fis-parser-sass
  14. * fis.require('parser-sass');
  15. * @property {Array} prefixes 用来配置 fis.require 前缀的查找规则的。默认:['fis3', 'fis']。
  16. * @property {Object} _cache 用来缓存模块加载,避免重复查找。
  17. */
  18. var slice = [].slice;
  19. var flag = false;
  20. var path = require('path');
  21. var fs = require('fs');
  22. var _ = require('./util.js');
  23. var isFile = _.isFile;
  24. var readFileSync = fs.readFileSync;
  25. var exports = module.exports = function() {
  26. var name = slice.call(arguments, 0).join('-');
  27. if (exports._cache.hasOwnProperty(name)) return exports._cache[name];
  28. // 第一次调用的时候做兼容处理老的一些用法。
  29. if (!flag) {
  30. flag = true;
  31. var global = fis.get('system.globalNPMFolder');
  32. if (global) {
  33. fis.log.warn('fis.set(\'system.globalNPMFolder\') is deprecated, please set fis.require.paths instead.');
  34. exports.paths.push(global);
  35. }
  36. var local = fis.get('system.localNPMFolder');
  37. if (local) {
  38. fis.log.warn('fis.set(\'system.localNPMFolder\') is deprecated, please set fis.require.paths instead.');
  39. exports.paths.unshift(local);
  40. }
  41. // 去重
  42. exports.paths = exports.paths.filter(function(item, idx, arr) {
  43. if (!/node_modules$/.test(item)) {
  44. fis.log.warn('The path `%s` in fis.require.paths is not end with `node_modules`, and it will be skipped.', item);
  45. return false;
  46. }
  47. return arr.indexOf(item) === idx;
  48. });
  49. if (!exports.paths.length) {
  50. exports.paths = [path.join(path.dirname(__dirname), 'node_modules')];
  51. }
  52. }
  53. var resolved = null;
  54. var paths = gatherAvailableNodePaths(exports.paths);
  55. var prefixes = exports.prefixes;
  56. var names = prefixes.map(function(prefix) {
  57. return prefix + '-' + name;
  58. });
  59. paths.every(function(dir) {
  60. names.every(function(name) {
  61. var ret = loadAsFileSync(path.join(dir, '/', name)) || loadAsDirectorySync(path.join(dir, '/', name));
  62. if (ret) {
  63. resolved = ret;
  64. }
  65. return !resolved;
  66. });
  67. return !resolved;
  68. });
  69. if (!resolved) {
  70. // 特殊处理 fis-parser-less
  71. if (name === 'parser-less') {
  72. names = ['fis-parser-less'];
  73. }
  74. fis.log.error('unable to load plugin [%s]', names.join('] or ['));
  75. }
  76. fis.log.debug('Resolved module %s to %s', name, resolved);
  77. return exports._cache[name] = require(resolved);
  78. };
  79. exports.paths = [];
  80. exports._cache = {};
  81. exports.prefixes = ['fis3', 'fis'];
  82. exports.extensions = ['.js'];
  83. function gatherAvailableNodePaths(paths) {
  84. paths = paths.concat();
  85. var start = paths.pop();
  86. var node_modules = paths.concat();
  87. var prefix = '/';
  88. if (/^([A-Za-z]:)/.test(start)) {
  89. prefix = '';
  90. } else if (/^\\\\/.test(start)) {
  91. prefix = '\\\\';
  92. }
  93. var splitRe = process.platform === 'win32' ? /[\/\\]/ : /\/+/;
  94. // ensure that `start` is an absolute path at this point,
  95. // resolving againt the process' current working directory
  96. start = path.resolve(start);
  97. var parts = start.split(splitRe);
  98. var dirs = [];
  99. for (var i = parts.length - 1; i >= 0; i--) {
  100. if (parts[i] === 'node_modules') continue;
  101. dirs = dirs.concat(
  102. prefix + path.join(
  103. path.join.apply(path, parts.slice(0, i + 1)),
  104. 'node_modules'
  105. )
  106. );
  107. }
  108. if (process.platform === 'win32') {
  109. dirs[dirs.length - 1] = dirs[dirs.length - 1].replace(":", ":\\");
  110. }
  111. return node_modules.concat(dirs);
  112. }
  113. function loadAsFileSync(x) {
  114. if (isFile(x)) {
  115. return x;
  116. }
  117. var extensions = exports.extensions;
  118. for (var i = 0; i < extensions.length; i++) {
  119. var file = x + extensions[i];
  120. if (isFile(file)) {
  121. return file;
  122. }
  123. }
  124. }
  125. function loadAsDirectorySync(x) {
  126. var pkgfile = path.join(x, '/package.json');
  127. if (isFile(pkgfile)) {
  128. var body = readFileSync(pkgfile, 'utf8');
  129. try {
  130. var pkg = JSON.parse(body);
  131. if (pkg.main) {
  132. var m = loadAsFileSync(path.resolve(x, pkg.main));
  133. if (m) return m;
  134. var n = loadAsDirectorySync(path.resolve(x, pkg.main));
  135. if (n) return n;
  136. }
  137. } catch (err) {}
  138. }
  139. return loadAsFileSync(path.join(x, '/index'));
  140. }