前言

这几周不加班,早早到家,闲来无事在 NAS 服务器上搭建了个 Jenkins,用了几天后觉得自带的主题有点单调。

Them Plguin

需要安装 Simple Theme PluginLogin Theme Plugin

怎么安装和使用就不说明了,参考官方最新的文档更为靠谱。

主要他们提供了加载 cssjs 的配置。

本地 Web 服务

本地开发时为了方便查看效果,我用 NodeJSKoa 在本地启动了一个 Web 服务,让 Theme Plugin 读取我本地的 cssjs 文件。

这样修改完 cssjs 文件后,刷新页面即可看到效果,而不需要每次把 cssjs 的文件内容配置到 Theme Plugin 中。

1
2
3
4
5
6
7
8
const Koa = require("koa");
const serve = require("koa-static-server");

const port = 4600;
const app = websockify(new Koa());

app.use(serve({ rootDir: "dist", rootPath: "/" }));
app.listen(port);

引入 Less

写了几句 css 后,发现没嵌套功能写的真难受,于是引入 Less,方便编写 css。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const less = require("less");

const renderLess = async (lessFilePath) => {
let lessFileContent = fs.readFileSync(lessFilePath, { encoding: "utf-8" });
let lessRenderRes = await less.render(lessFileContent);

let targetPath = path.join(
__dirname,
"../dist",
lessFilePath.substring("src/".length, lessFilePath.length)
);
let targetDir = path.dirname(targetPath);
let targetName = path.basename(targetPath, ".less") + ".css";
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
targetPath = path.join(targetDir, targetName);
fs.writeFileSync(targetPath, lessRenderRes.css, { encoding: "utf-8" });
return { path: targetPath.replace(path.join(__dirname, "../dist"), "") };
};

监听文件变化

既然都引入了 Less,那么肯定要引入 自动编译,同时为了后续热更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const glob = require("glob");
const chokidar = require("chokidar");

const watchAndRenderLess = () => {
glob("src/**/*.less", {}, function (er, files) {
files.forEach(renderLess);
});
const watcher = chokidar.watch("src/**/*.less");
watcher.on("all", async (e, filePath, stats) => {
if (e == "add" || e == "change" || e == "addDir") {
let result = await renderLess(filePath);
console.log(`${url}${result.path}`);
}
});
};

watchAndRenderLess();

现在就可以愉快的使用 Less 了。

热更新

每次编写样式后,都需要手动刷新页面才能看到效果,能不能自动热更新页面,不需要手动刷新页面呢?

使用三方库虽然方便,但自己尝试写一下也是不错的选择。

主要就是监听样式文件变化,然后通过 webScoket 通知页面,页面再加载新的样式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const websockify = require("koa-websocket");

const port = 4600;
const url = `http://localhost:${port}`;
const clients = new Set();

app.ws.use(function (ctx, next) {
clients.add(ctx.websocket);
ctx.websocket.onclose = () => {
clients.delete(ctx.websocket);
};
return next(ctx);
});

const watchAndRenderLess = () => {
// ...
const watcher = chokidar.watch("src/**/*.less");
watcher.on("all", async (e, filePath, stats) => {
if (e == "add" || e == "change" || e == "addDir") {
// ...
refresh(result.path);
}
});
};

const renderClientJs = () => {
let content = fs.readFileSync(path.join(__dirname, "client.js"), {
encoding: "utf-8",
});
content = content.replace(/\$\[port\]/g, port);
fs.writeFileSync(path.join(__dirname, "../dist", "client.js"), content, {
encoding: "utf-8",
});
};

const refresh = (filePath) => {
clients.forEach((client) => {
let data = { type: "refresh", path: filePath };
client.send(JSON.stringify(data));
});
};

renderClientJs();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// client.js
(function () {
// 此文件用于修改主题样式文件时,热更新样式用的。

let host = "localhost:$[port]";
let files = new Map();

let findTargetCss = () => {
let links = [...document.querySelectorAll('link[rel="stylesheet"]')];
for (const link of links) {
let url = new URL(link.href);
if (url.host === host) {
files.set(url.pathname, link);
}
}
};

findTargetCss();

let ws = new WebSocket(`ws://${host}/`);
ws.onmessage = (e) => {
console.log("message", e);
let data = JSON.parse(e.data);
if (data.type == "refresh") {
if (files.has(data.path)) {
let node = files.get(data.path);
let url = new URL(node.href);
let qs = new URLSearchParams(url.search);
qs.set("t", new Date().getTime());
url.search = qs.toString();
node.href = url.toString();
}
}
};
ws.onopen = (e) => {
console.log("open", e);
ws.send("hello world");
};
})();

通过 Theme Plugin 再把这个 client.js 引入,就可以实现热更新了。

上面的代码仅是 demo,为了快速解决问题随手写的。

主题效果

背景使用了 Bing 的今日壁纸,每天都会看到不一样的背景,整体是半透明的风格,整体颜色风格会受到背景颜色的影响,这样每天都可以感受到不一样的效果了。

下面图片是经过压缩的,背景效果有点模糊,没真实的看着丝滑。