Как вы определяете node_modules как externs в Closure Compiler?

У меня есть проект Node.js, который я хочу скомпилировать с помощью Closure Compiler. Я не хочу, чтобы он запускался в браузере/использовал браузер. В основном я хочу использовать функцию проверки типов. Я изначально получил компилятор для правильной работы, используя следующее:

java -jar compiler.jar -W VERBOSE 
                       --language_in ECMASCRIPT5_STRICT 
                       --externs closure-externs.js 
                       --js="lib/**.js"

Где closure-externs.js вручную определенные переменные и функции, которые я использовал из Node.js, довольно грубо:

// closure-externs.js

/** @constructor */function Buffer(something){}
function require(path){}
var process = {};
[...]

Оказывается, это работало только благодаря удаче. Нет никакого отслеживания зависимостей между файлами, поэтому вы можете иметь случаи, когда вы возвращаете тип {Foo}, и компилятор будет жаловаться, что он не существует (в зависимости от машины, в зависимости от порядка компиляции). Затем я узнал, что делаю все это неправильно и должен использовать --process_common_js_modules, чтобы компилятор выполнял отслеживание зависимостей, где я require("foo"). В настоящее время я вызываю такой компилятор:

java -jar compiler.jar -W VERBOSE 
                       --language_in ECMASCRIPT5_STRICT 
                       --externs externs/fs.js 
                       --js="lib/**.js"
                       --process_common_js_modules 
                       --common_js_entry_module app.js

Но это не работает:

 ERROR - required entry point "module$crypto" never provided
 ERROR - required entry point "module$dgram" never provided
 ERROR - required entry point "module$extend" never provided
 ERROR - required entry point "module$fs" never provided
 ERROR - required entry point "module$net" never provided
 ERROR - required entry point "module$q" never provided

Некоторые из этих модулей являются родными для Node.js(например, fs), тогда как другие содержатся в node_modules как q. Я не хочу запускать эти внешние модули через компилятор, поэтому я знаю, что мне нужно настроить externs файл для них. Я знаю, что https://github.com/dcodeIO/node.js-closure-compiler-externs для обычных Node.js externs, и я знаю, как их вызывать в компиляторе, но по какой-то причине когда я делаю что-то вроде --externs externs/fs.js, ошибка для module$fs сохраняется. Что я делаю неправильно?

Я знаю там другие флаги, такие как --module и --common_js_module_path_prefix, но я не уверен, что мне нужно использовать их, чтобы заставить это работать или нет. Мой Google-фу не смог найти ответы на правильное заклинание здесь.: (

Ответ 1

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

Обходные

Использовать пост-обработку для добавления внешних требований о требованиях

В этом случае вы полностью опускаете любые операторы require для внешних модулей. Компилятор будет обрабатывать только код с внутренними требованиями операторов и модулей. После компиляции вы добавили внешние требования:

Заголовок JS должен быть превентивным

var crypto = require('crypto');

Источник для компиляции

console.log(crypto);

Поскольку crypto объявлен в extern, компилятор правильно распознает тип и имя символа.

Псевдоним требует вызовов

Когда указан параметр --process_common_js_modules, компилятор распознает операторы require и расширяет их аналогично тому, как макросы работают на других языках. Путем сглаживания операторов require, которые должны оставаться внешними, компилятор не узнает их и, следовательно, не расширяет их.

Источник для компиляции

var externalRequire = require;
/** @suppress {duplicate} this is already defined in externs */
var crypto = externalRequire('crypto');
console.log(crypto)