本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: https://www.huangyunkun.com/2018/01/13/sited-plugin-gulp-configuration/
今天找漫画的时候又想到多多猫了,之前用过一下,当时写插件还是用的记事本在xml中直接编写js,那个体验很差,而且代码测试也很复杂。
今天又需要插件了,自然想换点花样来做,首先考虑的就是使用构建工具来处理大部分问题。这里用的是Gulp。
模板替换和文件生成
我们的目标文件只有一个,那就是index.sited.xml。而这个文件又分了两个部分,首先是xml的声明,包含了一些插件信息,其次是我们的js代码。
首先做的是将这两者分开,分别创建index.xml和index.js文件。
<?xml version="1.0" encoding="utf-8"?>
<sited ver="1" debug="1" engine="32" schema="1">
<meta guid="<%=app.guid%>">
<title><%= app.title %></title>
<intro><%= app.intro %></intro>
<author><%= app.author %></author>
<url><%= app.url %></url>
<encode>utf-8</encode>
<expr><%= app.expr%></expr>
</meta>
<main dtype="1" durl="<%= app.url %>">
<home>
<hots cache="1d" title="首页" method="get" parse="hots_parse" url="<%= app.url %>"/>
</home>
<book cache="1d" method="get" parse="book_parse" />
<section cache="1" method="get" parse="section_parse" />
</main>
<script>
<require>
<item url="http://sited.noear.org/addin/js/cheerio.js" lib="cheerio"/>
</require>
<code>
<![CDATA[
<%-js%>
]]>
</code>
</script>
</sited>
这个文件使用了ejs语法,等会儿我们用ejs模板引擎来生成最终文件
function hots_parse(url, html) {
return JSON.stringify([]);
}
function book_parse(url, html) {
return JSON.stringify([]);
}
function section_parse(url, html) {
return JSON.stringify([]);
}
这里面的三个方法名称和xml中的对应。
然后准备一份config.js文件来保存插件信息
const app = {
"title": "",
"intro": "",
"author": "",
"url": "http://",
"expr": "\\.domain\\.com",
"guid": "xxxx"
};
module.exports = app;
然后在gulp配置中添加gulp-ejs
gulp.task('build', function () {
var jsContent = fs.readFileSync("./src/index.js", "utf8");
var app = require('./config.js');
gulp.src("index.xml")
.pipe(ejs({
app: app,
js: uglifyJS.minify(jsContent).code
}))
.pipe(rename("index.sited.xml"))
.pipe(gulp.dest("./dist"));
});
js文件我是压缩了一下再放进去,如果压缩影响了你的代码功能,你可以考虑把压缩取消掉。
这样当我们运行npm build的时候就能生成目标文件了。
开发服务器
当目标文件生成好了,我们就需要把它放到app中测试一下,这里本地搭建一个简单的文件服务器,然后通过扫描二维码直接将文件弄到手机上。
还是在gulp中,我们使用gulp-serve和qrcode-terminal,另外需要internal-ip来获取一个对外可用的IP地址。调试用的手机和电脑要在一个网络中。
gulp.task('qr', function () {
qrcode.generate("http://" + internalIp.v4.sync() + ":" + port + "/index.sited.xml", function (qrcode) {
console.log(qrcode);
});
});
gulp.task('server', ['qr'], serve({
root: ['dist'],
port: port,
hostname: internalIp.v4.sync()
}));
为了方便起见,当我们修改了js代码以后,最好能够自动刷新,这里用gulp-watch监控文件变动。
gulp.task('watch', ['server'], function () {
return watch(['src/index.js', 'config.js', 'index.xml'], function () {
gulp.start('build');
});
});
现在运行npm run watch

拿出app扫描二维码就可以快速运行我们的新插件了。
自动化测试
多多猫插件写的时候还有一个问题就是调试很麻烦,有时候错了需要仔细脑补一下,虽然可以看日志,但是有时候日志并不能帮上多大忙。
除了开发中的问题外,还有一个问题就是插件完成后可能会失效(原因各种各样),有时候并不能第一时间知道问题,需要一个有效的机制来控制,尽可能早的知道问题。
这里就需要引入单元测试和集成测试了。
单元测试用在开发中,方便快速获得反馈,避免不停的在app上调试。集成测试会和目标网站实际通讯,以便快速验证插件是否还有效。
先来看看单元测试,首先随便抓几个网页下来,保持在项目中,测试的时候直接用这些数据就行。我这里用的mocha
var expect = require('chai').expect;
var cheerio = require('cheerio');
var fs = require('fs');
eval(fs.readFileSync('./src/index.js') + '');
describe('index.js', function () {
it('should parse hots', function () {
const html = fs.readFileSync('./test/data/hots_response.html');
const response = JSON.parse(hots_parse(null, html));
expect(response.length).to.equal(??);
expect(response[0].name).to.equal('???');
expect(response[0].url).to.equal('???');
expect(response[0].logo).to.equal('???');
});
it('should parse book', function () {
const html = fs.readFileSync('./test/data/book_response.html');
const response = JSON.parse(book_parse(null, html));
expect(response.name).to.equal('???');
expect(response.sections.length).to.equal(??);
expect(response.sections[0].name).to.equal('???');
expect(response.sections[0].url).to.equal('???');
});
it('should parse section', function () {
const html = fs.readFileSync('./test/data/section_response.html');
const response = JSON.parse(section_parse(null, html));
expect(response.length).to.equal(??);
expect(response[0]).to.equal('http://???');
});
});
原则上讲只要这几个测试通过,那么基本功能就没有大问题。测试中的???请替换成自己真实需要的数据。
这里面最关键的就是eval(fs.readFileSync('./src/index.js') + '');
因为我们的index.js并没有exports出任何东西,只是单纯写了三个方法,所以只有通过eval把方法放到上下文中。
集成测试就是真实请求目标网站,然后判断每个步骤都有返回且不为空。
var expect = require('chai').expect;
var cheerio = require('cheerio');
var fs = require('fs');
var request = require('request');
var prettyjson = require('prettyjson');
eval(fs.readFileSync('./src/index.js') + '');
describe('integration', function () {
it('should able to parse all', function (done) {
this.timeout(0);
request('???', function (error, response, body) {
if (error) done(error);
var parsedResult = JSON.parse(hots_parse(null, body));
console.log(prettyjson.render(parsedResult));
expect(parsedResult.length > 0).to.equal(true);
request(parsedResult[0].url, function (error, response, body) {
if (error) done(error);
parsedResult = JSON.parse(book_parse(null, body));
console.log(prettyjson.render(parsedResult));
expect(parsedResult.sections.length > 0).to.equal(true);
request(parsedResult.sections[0].url, function (error, response, body) {
if (error) done(error);
parsedResult = JSON.parse(section_parse(null, body));
console.log(prettyjson.render(parsedResult));
expect(parsedResult.length > 0).to.equal(true);
done();
});
});
});
});
});
这个是一层层嵌套的,回调可以用别的库简化一下,但是这里整体比较简单,真的没有必要。
最后配置一下自己的CI服务,我用的bitbucket

运行效果如下

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: https://www.huangyunkun.com/2018/01/13/sited-plugin-gulp-configuration/