上文(JavaScript编译vm模板(一))中介绍了
vm文件编译为html文件的方法,并增加了watchpack进行实时监测以便vm文件变化时自动编译。本文我们要进一步进行优化,实现静态文件服务器以便展示生成的html文件,并实现vm变化后自动刷新html页面
涉及到的npm包
源码
const http = require('http');
const path = require("path");
const fs = require('fs');
const WebSocket = require('ws')
const WebSocketServer = WebSocket.Server;
const open = require('open');
const Watchpack = require("watchpack");
const velocity = require('velocityjs');
// 监听文件变化
const wp = new Watchpack({
aggregateTimeout: 100,
poll: true,
followSymlinks: true,
ignored: "**/.git"
});
wp.watch({
files: [
path.join(__dirname, 'day.vm'),
path.join(__dirname, 'hour.vm')
],
startTime: Date.now() - 10000
});
const dayContext = {
isNormalDay: false,
month: 12,
dt: ["11/01", "11/02", '11/03']
};
const hourContext = {
lastStr: '周三',
isTop6Hour: true
};
const htmlPort = Math.floor(Math.random() * 1000 + 8000);
const wsClientPort = Math.floor(Math.random() * 1000 + 9000);
const wsClientS = [];
const clientWS = `
<script>
const ws = new WebSocket('ws://localhost:${wsClientPort}')
ws.onmessage = function (evt) {
if (window.location.href.indexOf(evt.data) !== -1) {
window.location.reload();
}
};
</script>
`;
wp.on("change", function (filePath, mtime, explanation) {
let message = '';
console.log(`change:${filePath}...`)
if (filePath.indexOf('day') !== -1) {
message = 'day'
} else if (filePath.indexOf('hour') !== -1) {
message = 'hour'
}
wsClientS.forEach(ws => {
ws.send(message);
})
});
// 创建本地服务器来从其接收数据
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html; charset=UTF-8' });
if (req.url === '/day.html') {
const vmContent = velocity.render(
fs.readFileSync(
path.join(__dirname, 'day.vm'), 'utf-8'
), dayContext
);
res.end(vmContent.slice(
0,
vmContent.indexOf('</body>')) + clientWS + '</body></html>'
);
} else if (req.url === '/hour.html') {
const vmContent = velocity.render(
fs.readFileSync(path.join(__dirname, 'hour.vm'), 'utf-8'
), hourContext
);
res.end(vmContent.slice(
0,
vmContent.indexOf('</body>')) + clientWS + '</body></html>'
);
} else {
res.end();
}
}).listen(htmlPort, () => {
console.log(`listen:http://127.0.0.1:${htmlPort}...`);
open(`http://127.0.0.1:${htmlPort}/day.html`, {
app: { name: 'chrome' }
}
);
});
// 获取自动刷新
(new WebSocketServer({
port: wsClientPort
})).on('connection', function connection(ws) {
wsClientS.push(ws);
});
需要注意的几个关键点:
- 为了避免打开多个服务器以及冲突,端口号是随机生成的
- 当
vm文件变化时,我们是reload了整个页面,实际时,可以通过WebSocket将编译后的结果传给客户端,客户端只更新部分的页面dom(如body等),这样就不必刷新整个页面了。 - 我们的静态文件服务器和
WebSocket实际上是两个单独的服务器,各自有各自的端口 - 在
open@8.3.0官网上,打开谷歌浏览器写的name是google chrome,这是有问题的,实际上应该按照上文chrome来设置