azproduction / lmd

LMD - JavaScript Module-Assembler for building better web applications :warning: Project is no longer supported :warning:
http://azproduction.ru/lmd/
MIT License
449 stars 27 forks source link

Require и relative path #197

Closed lomadurov closed 9 years ago

lomadurov commented 9 years ago

Насколько реально использовать relative path в require()

Пример:

+-root/                 |
  |                        
  +-.lmd/               |   
  +-modules/            |
  |  |                     
  |  +-app.js           | ./app.js; main;
  |  +-blocks/          |
  |  |  |                  
  |  |  +-index.js      | ./blocks/index.js | require('../blocks') === require('../index') === require('./index')
  |  |  +-block.js      | ./blocks/block.js | require('../blocks/block') === require('./block')
  |  |  +-type/         |
  |  |  |  |              
  |  |  |  +-text.js     | ./blocks/type/text.js | require('../blocks/type/text') === require('./type/text')
  |  |  |  +-video.js    | ./blocks/type/video.js | require('../blocks/type/video') === require('./type/video')
  |  +-util/
  |  |  |
  |  |  +-index.js      | ./util/index.js | require('../util') === require('./index')
  |  |  +-test.js       | ./util/test.js | require('../util/test') === require('./test')
  |  |  +-block.js      | ./util/test.js | require('../util/block') === require('./block') !== require('./block') (blocks/block)

Насколько я понимаю на текущий момент require не передаёт sandbox из которого он вызывается, тем самым точно определить разницу между require('./block') из util и require('./block') из blocks не представляется возможным?

Если бы в *:rewrite-shortcut передавался ещё и sandbox moduleName, тогда плагин для этого добра занял бы пару строк.

lomadurov commented 9 years ago

Разобрался:

/*global sandbox*/
(function (sb) {
    'use strict';

    var _defaults = function (obj) {
        for (var i = 1, length = arguments.length; i < length; i++) {
            var source = arguments[i];
            for (var prop in source) {
                if (obj[prop] === void 0) {
                    obj[prop] = source[prop];
                }
            }
        }
        return obj;
    };

    sb.on('lmd-register:decorate-require', function (moduleName, require) {
        var currentDirectory = moduleName.split('/');

        // Remove filename
        currentDirectory.pop();

        var localRequire = function (moduleName) {
            var relative,
                path;

            // Check is relative path (start at ./ || ../)
            if (moduleName.charAt(0) === '.') {
                relative = moduleName.split('/');
                path = currentDirectory.slice();

                while (true) {
                    if (relative[0] === '..') {
                        relative = relative.slice(1);
                        path.pop();
                        continue;
                    } else if (relative[0] === '.') {
                        relative = relative.slice(1);
                        continue;
                    }
                    break;
                }
                path = path.concat(relative).join('/');

                return require(sb.modules[path.concat('/index')] ? path.concat('/index') : path);
            }
            return require(moduleName);
        };
        return [moduleName, _defaults(localRequire, require)];
    })
}(sandbox));
{
   // ...
   "modules": {
      "${subdir.reverse().slice(1).join('/')}/${file}": "modules/**/*.js"
   }
   // ...
}