Поделюсь небольшими экспериментами с дублированием функциональности require в Node.js. Практика скорее порочная, но немного проливает свет на проблемы этой популярной платформы. Изначальная мотивация в подобных изысканиях возникла после следующих наблюдений.


Существует некое концептуальное различие в способах подключения внешних библиотек и файлов проекта. А стандартный механизм для этого используется один и тот же. Второй момент, который меня смущает — это несколько замороченная логика работы самого require.


В итоге захотелось по крайней мере свои файлы подключать самодельным, но более прозрачным способом. Параллельно добавив несколько дополнительных фич. Так появились нижеописанные функции.


get_modules =( string, modules ={} )->
    groups =string .split ' '
    for group in groups
        items =group .split ':'
        id =items[ 0 ]
        named =items .length > 1
        name =if named then items[ 1 ] else id .replace( /\-/g, '_' )
        obj =require id
        obj =obj[ name ] if named and obj[ name ]
        modules[ name ] =obj
    modules

вспомогательная функция подключения стандартных модулей. Работает следующим образом. После, например modules =get_modules 'fs path coffeescript vm' в объекте modules мы получим стандартные модули fs, path и другие, обращаться, к которым соответсвенно можно будет modules .[имя модуля] .[имя функции].


Теперь


read =( file )->
    path =modules .path .join __dirname, file
    modules .fs .readFileSync path, 'utf8'

— возвращает содержимое исходного файла.


compile =( coffee, file )->
    options = inlineMap: false, sourceMap: true, bare: true, filename: file
    res =modules .coffeescript .compile coffee, options
    res .js

— транслирует CoffeeScript в JavaScript.


evaluate =( js, filename ='', lineOffset =0, columnOffset =0 )->
    modules .vm .runInThisContext js, { filename, lineOffset, columnOffset }

— исполняет JavaScript код.


И всё вместе, в случае, если мы хотим обернуть наш код в некую wrapper-функцию:


get_wrapper =( id, args )->
    file =id + '.coffee' #путь к файлу
    str =@read( file ) .replace( /\n/g, "\n\t" ) #добавляем отступы
    coffee ="( #{ args } )->\n\t#{ str }" #собственно "оборачиваем" в функцию
    js =@compile coffee, file
    @evaluate js, file#, 1, 0

где args — строка с именами переменных через запятую, которые станут доступны как "глобальные" в данном модуле.


https://gist.github.com/jenya239/78b7c819ee8e93490d7d384a204c44bf