Пользовательский плагин Gulp.js: TypeError "Путь должен быть строкой. Получено не определено"
Я нашел несколько тем на Stackru о TypeError: Path must be a string
, хотя я не смог применить предложенные решения к моему делу.
Я пытаюсь создать плагин Gulp, который подключается к (платному) сервису javascriptobfuscator.com и использую их POST
API, чтобы запутать мой JS.
Задание Gulp выглядит так:
var gulp = require('gulp'),
jso = require('./jsobfuscator');
gulp.task('jso', function() {
// .jsx contain extendscript language, which as far as
// the service is concerned, could be treated as .js
return gulp.src('.src/app/jsx/photoshop.jsx')
.pipe(jso())
.pipe(gulp.dest('./dist'))
});
jsobfuscator.js
Файл содержит следующий код:
var through = require('through2'),
http = require('http'),
gutil = require('gulp-util'),
Readable = require('stream').Readable
module.exports = function() {
/**
* @this {Transform}
*/
var transform = function(file, encoding, callback) {
var that = this;
var proj = {};
proj.APIKey = "/* MyAPIKey*/";
proj.APIPwd = "/* MyAPIPwd*/";
proj.Name = "DoubleUSM";
proj.ReorderCode = true;
proj.ReplaceNames = true;
proj.EncodeStrings = true;
proj.MoveStrings = true;
proj.MoveMembers = true;
proj.DeepObfuscate = true;
proj.SelfCompression = true;
// Unsure about these two...
proj.CompressionRatio = "Auto";
proj.OptimizationMode = "Auto";
var appJS = new Object();
appJS.FileName = "app.js";
appJS.FileCode = file.contents.toString('utf8');
// Will try to implement multiple files later on
proj.Items = [appJS];
var postData = JSON.stringify(proj);
// Length is OK
gutil.log ("Length: " + Buffer.byteLength(postData, 'utf-8'))
var options = {
host: 'service.javascriptobfuscator.com',
path: '/HttpApi.ashx',
method: 'POST',
headers: {
'Content-Type': 'text/json',
'Content-Length': Buffer.byteLength(postData, 'utf-8')
}
};
callback = function(response) {
response.setEncoding('utf8');
var str = '';
response.on('data', function(chunk) {
str += chunk;
});
response.on('end', function() {
// I get the correct response here!
gutil.log(JSON.stringify(JSON.parse(str), null, ' '));
var resObj = JSON.parse(str);
// Converting the received string into a Buffer
var fileStream = new Readable();
// resObj.Items[0].FileCode is where the obfuscated code belongs
fileStream.push(resObj.Items[0].FileCode);
fileStream.push(null);
that.push(fileStream);
callback();
});
}
var req = http.request(options, callback);
req.write(postData);
req.end();
};
return through.obj(transform);
};
Когда я запускаю задачу gulp, я, очевидно, получаю правильный ответ из кода javascriptobfuscator (как вы можете видеть ниже), но что-то не так в той части, где я передаю файл к месту назначения, потому что я получаю:
(master)* gulp jso
[15:13:30] Using gulpfile ~/Dropbox/Developer/PROJECTS/DOUBLE USM/gulpfile.js
[15:13:30] Starting 'jso'...
[15:13:31] Lenght: 21897
[15:13:32] {
"Type": "Succeed",
"Items": [
{
"FileName": "app.js",
"FileCode": /* ... Long, horrible, properly obfuscated blob here... */
}
],
"ErrorCode": null,
"Message": null,
"FileName": null,
"LineNumber": null,
"ExceptionToString": null
}
path.js:7
throw new TypeError('Path must be a string. Received ' + inspect(path));
^
TypeError: Path must be a string. Received undefined
at assertPath (path.js:7:11)
at Object.resolve (path.js:1146:7)
at DestroyableTransform.saveFile [as _transform] (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/vinyl-fs/lib/dest/index.js:36:26)
at DestroyableTransform.Transform._read (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/vinyl-fs/node_modules/readable-stream/lib/_stream_transform.js:184:10)
at DestroyableTransform.Transform._write (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/vinyl-fs/node_modules/readable-stream/lib/_stream_transform.js:172:12)
at doWrite (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/vinyl-fs/node_modules/readable-stream/lib/_stream_writable.js:237:10)
at writeOrBuffer (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/vinyl-fs/node_modules/readable-stream/lib/_stream_writable.js:227:5)
at DestroyableTransform.Writable.write (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/vinyl-fs/node_modules/readable-stream/lib/_stream_writable.js:194:11)
at DestroyableTransform.ondata (/Users/davidebarranca/Dropbox/Developer/PROJECTS/DOUBLE USM/node_modules/through2/node_modules/readable-stream/lib/_stream_readable.js:546:20)
at emitOne (events.js:96:13)
По общему признанию я не эксперт плагинов Gulp - я пытаюсь создать функциональность для моего личного использования. Похоже, я довольно близко, но я застрял в этом тупике на некоторое время, и мне нужна помощь более опытных.
заранее спасибо
Наполовину рабочее обновление
Модификация response.on('end')
Обратный вызов следующим образом, я смог наконец написать файл:
response.on('end', function() {
var resObj = JSON.parse(str);
var fileStream = new Readable();
fileStream.push(resObj.Items[0].FileCode);
fileStream.push(null);
// Manually creating a new Vinyl file
var jsFile = new Vinyl({
cwd: file.cwd,
base: file.base,
path: file.path,
contents: fileStream
});
return that.push(jsFile);
// callback();
});
Я должен был закомментировать финал callback()
Тем не менее, в противном случае я бы столкнулся с ошибкой, указывающей на response.setEncoding('utf8');
линия, будучи response
не определено.
Проблема сейчас в том, что кажется, что задача, в некотором роде, никогда не заканчивается. Консоль говорит Starting 'jso'...
, файл записан, консоль возвращается, но нет Finished 'jso' after nn ms
и, что хуже всего, я совершенно не в состоянии связать больше глоточных задач потом, так что если я:
gulp.task('jso1', function() {
return gulp.src('.src/app/jsx/photoshop.jsx')
.pipe(jso())
.pipe(gulp.dest('./dist'))
});
gulp.task('jso2', ['jso1'], function() {
return gulp.src('.src/app/app.js')
.pipe(jso())
.pipe(gulp.dest('./dist'))
});
// then in the Terminal:
$ gulp jso2
Единственное, что я получаю, это jso1
начало, очевидно работающее, но никогда не заканчивающееся; jso2
никогда не бежит.
1 ответ
Многочасовые царапины на голове заставили меня прийти к ответу. Вкратце, в моем плагине Gulp:
- Я должен был вернуть новый виниловый файл в
response.on('end')
обратный вызов: файлcontents
свойство должно быть потоком от ответа сервера. - Основной недостаток моего полу-рабочего решения в том, что я дал одно и то же имя (
callback
) две очень разные функции. Одним из них являетсяcallback
от начальногоtransform
функция; другой являетсяhttp.request
Перезвоните. Закомментируем последнееcallback()
позвони, послеreturn that.push(jsFile);
помешал завершению всей задачи Gulp.
Полный рабочий код выглядит следующим образом:
var through = require('through2'),
http = require('http'),
gutil = require('gulp-util'),
Readable = require('stream').Readable,
Vinyl = require('vinyl');
module.exports = function() {
var transform = function(file, encoding, callback) {
if (file.isNull()) { return callback(null, file) }
var that = this;
var proj = {};
proj.APIKey = "/* MyAPIKey */";
proj.APIPwd = "/* APIPwd */";
proj.Name = "Project";
proj.ReorderCode = true;
proj.ReplaceNames = true;
proj.EncodeStrings = true;
proj.MoveStrings = true;
proj.MoveMembers = true;
proj.DeepObfuscate = true;
proj.SelfCompression = true;
proj.CompressionRatio = "Auto";
proj.OptimizationMode = "Auto";
var appJS = new Object();
appJS.FileName = "app.js";
appJS.FileCode = file.contents.toString('utf8');
proj.Items = [appJS];
var postData = JSON.stringify(proj);
var options = {
host: 'service.javascriptobfuscator.com',
path: '/HttpApi.ashx',
method: 'POST',
headers: {
'Content-Type': 'text/json',
'Content-Length': Buffer.byteLength(postData, 'utf-8')
}
};
/* Renamed to avoid confusion with transform's callback */
postCallback = function(response) {
response.setEncoding('utf8');
var str = '';
response.on('data', function(chunk) {
str += chunk;
});
response.on('end', function() {
var resObj = JSON.parse(str);
var fileStream = new Readable();
fileStream.push(resObj.Items[0].FileCode);
fileStream.push(null);
/* Return a new Vinyl File */
var jsFile = new Vinyl({
cwd: file.cwd,
base: file.base,
path: file.path,
contents: fileStream
});
that.push(jsFile);
callback();
});
}
var req = http.request(options, postCallback);
req.write(postData);
req.end();
};
return through.obj(transform);
};
Возможно, есть лучшие способы вернуть файл Vinyl без создания нового.
Другим улучшением было бы сгруппировать все исходные файлы и сделать один http-вызов API javascriptobfuscator (фактически можно добавить несколько файлов в proj.Items
массив), но я понятия не имею, как сгруппировать файлы в исходном коде, передать их все сразу плагину Gulp, а затем разделить их позже.