作者:李帅杰
插件功能:用于根据指定目录文件变化自动刷新指定页面的whistle插件。
一、需求背景:
前端页面联调时,F5 作为 web 开发常用刷新调试驱动键,已经深深刻在每个开发的心中。还在为修改页面不停的手动刷新而烦恼么?还在寻找其他 F5 替代方案么?如何优雅的释放 F5,请看下文~。
二、目标拆解:
假如我们自己来开发一种替代 F5 的文件刷新方案,可以从三个目标来分析:
1)文件修改监听——目标是刷新页面,但页面刷新的前提是代码的变动修改,捕捉文件修改事件成为我们优先解决的问题;
2)页面刷新——页面刷新很简单,但是如何通知到页面进行刷新呢;
3)修改通知——这个是我们需要解决的重点;
三、解决方案(whistle 插件采用 fs 而非 gulp,此处借 gulp 简单介绍下原理):
有了问题和目标,思考下每个问题的解决方案:
1)文件修改监听——
a、gulp 非常 nice 的自动化构建工具
b、node 的 fs 模块(livereload 插件通过 fs 模块实现监控)
c、其他
2)页面刷新——js 方法,location.reload(x);
3)修改通知——开启本地 svr,浏览器长链接监听(常用的观察者模式);
基于 node svr+websock 服务
四、开发实战:
方案已经枚举好,接下来就是开发实践:
(一)环境准备和代码实现(代码可在附件下载):
1)项目目录下,安装需要的 js 模块
npm i -s gulp
npm i -s ws
2)服务端代码编写
const WebSocket = require('ws');
const port = 8080;
function startSvr() {
console.log("start svr port:"+port);
var wss = new WebSocket.Server({
port: port
});
var connection = {};
wss.on('connection', function(ws) {
console.log("ws 已经连接");
ws.on('message', function(message) {
console.log("收到message:"+message);
msg = JSON.parse(message);
if (msg.type === 'test') {
connection[msg.id] = ws;
console.log('received: %s', JSON.stringify(msg));
if (!!connection[msg.id]) connection[msg.id].send(JSON.stringify(msg));
} else {
wss.clients.forEach(function each(client) {
client.send(message);
});
}
});
});
}
module.exports = {
start:startSvr
};
3)客户端监听代码编写
var ws = new WebSocket('ws://localhost:8080');
ws.onopen = function() {
console.log('open');
};
ws.onclose = function() {
console.log('onclose');
};
ws.onmessage = function(event) {
console.log('event,', event.data); //拿到的返回数据
var json = JSON.parse(event.data);
if(json.command=="reload"){
location.reload(1);
}else if(json.command=="javascript"){
eval(json.text);
}else if(json.command=="replace"){
document.getElementsByTagName("html")[0].innerHTML = json.text;
}
};
4)gulp 监听配置文件编写(此处 gulp 采用 4.0.2 版本)
const {
series,
parallel,
watch,
src,
dest
} = require('gulp');
const WebSocket = require('ws');
const appsvr = require('./appsvr.js');
const watcher = watch(['*']);//此处监听目录下所有文件
// const fs = require('fs');
let ws = "";
//日志工具类
let showlog = function (svr) {
var des = "";
for (var name in svr) {
des += name + ":" + svr[name] + ";\n";
}
console.log(des);
};
//服务开启
function webserver() {
appsvr.start();
setTimeout(function () {
ws = new WebSocket('ws://localhost:8080');
ws.on('open', () => {
let msg = {
command: 'init',
text: ""
};
ws.send(JSON.stringify(msg));
});
ws.on('error', err => {
console.log(err);
});
ws.on('message', data => {
console.log(data);
});
ws.on('close', (code, reason) => {
console.log(code);
console.log(reason + ':' + typeof reason);
});
}, 2000);
}
//监听文件变化
watcher.on('change', function (path, stats) {
console.log(`File ${path} was changed`);
//发送给监听者的动作
let msg = {
command: 'reload',
text: "reload"
};
ws.send(JSON.stringify(msg));
});
exports.webserver = webserver;
//默认出发,相当于main函数
exports.default = parallel(function () {
console.log("running");
}, webserver);
5)客户端 js 监听文件如何嵌入页面?
a、通过 script 标签的方式手动嵌入,需要手动修改文件,且事后容易忘记删除;
<script type=“text/javascript” src=“./f5.js”></script>
b、基于 whistle 的优雅嵌入,会自动对匹配的页面(html)无感知嵌入指定 js:
whistle 命令:jsAppend
daoju.qq.com/xxx/ jsAppend://daoju.qq.com/xxx/js/f5.js
6)启动服务,刷新浏览器启动监听
7)文件修改,观察效果
(二)其他解决方案实现及问题:
其他常用方案**:**
实现和问题:
- 实现方式:通过插件生成的本地服务地址来进行自动刷新访问,比如:
访问 localhost:3000,查看本地未分离文件,适合重构开发;
- 问题:活动开发前端联调是以线上活动域名 url 访问来进行开发和测试,且需要配合 host 配置,就不太适合。
五、基于 whistle 的 livereload 插件,让刷新更优雅
通过上述实践我们释放了 F5,但是打开项目目录,发现新增了一堆的 js,跟我们的项目格格不入,如何更优雅的释放 F5 呢?
whistle 插件化——目前已经开发整理成了 whistle 插件,地址如下:
npm 地址:npm.taobao.org/package/whi…
此处感谢 avenwu 大神对 whistle 插件化的专业指导和支持~
1)如何安装:
注意:whistle 需要升级到最新版本
npm i -g whistle.livereload
安装后:
2)使用方案:
#pattern whistle.livereload://需要监控的项目目录
daoju.qq.com/xxx/ whistle.livereload://D:\xxx\
关注【IVWEB社区】公众号获取每周最新文章,通往人生之巅!