本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
转载自夜明的孤行灯
本文链接地址: 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/