一. 引言
自我介绍:大家好,我是一名前端小白,听闻前端已死,遂记录自己在学习esbuild过程中解决的问题,将对一些比较好的自我实践内容进行分享。一起学习卷起来吧。
二. 关于esbuild
esbuild出现已有很长的时间,上面是来自官网的打包速度图,这张图让无数开发想尝试esbuild,而文档和复杂配置让人望而却步,用于生产实践还是像webpack一样复杂。
三. 如何配置scss文件并且实现px2rem
对于css,esbuild支持了内置的loader,不用再引用三方loader,对于sass也是如此。前端大多习惯使用sass语法进行开发,过程中仍然需要配置esbuild-sass-plugin对sass语法解析。
代码分享
loader: {
".scss": "text",
},
plugins: [
{
name: "scss",
setup(build) {
build.onLoad({ filter: /\.scss$/ }, async (args) => {
const { css } = sass.renderSync({
file: args.path,
});
const result = await postcss([postcsspx2rem({remUnit: 75,propList: ["border"],exclude: /node_modules/i,})]).process(css.toString(), {
from: args.path,
to: args.path,
});
return {
contents: result.css,
loader: "css",
};
});
},
},
]
上面代码将scss转译css,并支持pxtorem页面自适应布局。查阅不到相关的配置,我就想到了chatgpt,然而它给我的答案也不能解决我的问题,经过反复的摸索终于尝试成功。
1.remUnit: 75 的设置问题: 这个其实比较随意主要还是和根节点的fontSize成比例就行,一般以750px宽度(客户端视觉稿的规范宽度)是设置静态html中写入fontsize为75px, 或者你这里设置100也行,那就设置静态html中写入fontsize为100px,这个的实现如下,我将esbuild执行完毕后生成html,html中插入自执行的宽度监听变化的js。这是一种较多使用的方案,代码如下:
esbuild
.build({
})
.then(async (res) => {
const fileName = path.join(__dirname + "/dist/index.html");
await fse.ensureFile(fileName);
await fse.writeFileSync(
fileName,
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./index.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
</head>
<body>
<div id="root"></div>
</body>
<script src="./index.js"></script>
<script>
(function (doc) {
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>');
var root = doc.querySelector("html");
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = root.getBoundingClientRect().width;
root.style.fontSize = Math.min(100, (clientWidth / 10)) + "px";
};
window.addEventListener(resizeEvt, recalc, false);
return recalc();
})(document);
</script>
</html>
`
);
app.listen(3006, () => {
console.log(`> Local: http://localhost:3006/`);
});
});
2.效果展示
四. 如何使用字体图标库
1.对一些矢量图标图如阿里图标库的文件后缀添加loader
loader: {
".scss": "text",
".eot": "file",
".woff": "file",
".ttf": "file",
},
- 将图标文件放到项目中
3.设置全局样式
@font-face {font-family: 'iconfont';
src: url('./styles/iconfont/a.eot'); /* IE9*/
src: url('./styles/iconfont/a.woff') format('woff'), /* chrome、firefox */
url('./styles/iconfont/a.ttf') format('truetype'); /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
使用:
<span className="iconfont"></span>
五. 开发模式下的热重载
这个方案是将监听文件变化的js插入到本地开发html中。从而实现热重载。
const livereload = require("livereload");
const lrserver = livereload.createServer();
lrserver.watch(__dirname + "/dist");
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>');
总结
全部代码如下:
const esbuild = require("esbuild");
const path = require("path");
const serve = require("koa-static");
const Koa = require("koa");
const fse = require("fs-extra");
const postcsspx2rem = require("postcss-px2rem-exclude");
const app = new Koa();
const sass = require("sass");
const postcss = require("postcss");
// 启动编译好后自动刷新浏览器
const livereload = require("livereload");
const lrserver = livereload.createServer();
lrserver.watch(__dirname + "/dist");
// 使用静态服务
app.use(serve(path.join(__dirname + "/dist")));
esbuild
.build({
entryPoints: [path.resolve(__dirname, "./app.tsx")],
outfile: path.resolve(__dirname, "./dist/index.js"),
sourcemap: true,
bundle: true,
minify: true,
target: ["esnext"],
watch: {
onRebuild(error, result) {
if (error) console.error("watch build failed:", error);
else {
console.log("\x1B[36m%s\x1B[39m", "watch build succeeded");
console.log("watch build succeeded:", result);
}
},
},
format: "esm",
loader: {
".scss": "text",
},
plugins: [
{
name: "scss",
setup(build) {
build.onLoad({ filter: /\.scss$/ }, async (args) => {
const { css } = sass.renderSync({
file: args.path,
});
const result = await postcss([
postcsspx2rem({
remUnit: 75,
//过滤border 不转换
propList: ["border"],
exclude: /node_modules/i,
}),
]).process(css.toString(), {
from: args.path,
to: args.path,
});
return {
contents: result.css,
loader: "css",
};
});
},
},
],
})
.then(async (res) => {
const fileName = path.join(__dirname + "/dist/index.html");
// 创建文件,如果文件不存在直接创建,存在不做任何事情
await fse.ensureFile(fileName);
// 把下面内容写入dist中的index.html文件中
await fse.writeFileSync(
fileName,
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./index.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
</head>
<body>
<div id="root"></div>
</body>
<script src="./index.js"></script>
<script>
(function (doc) {
document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] +
':35729/livereload.js?snipver=1"></' + 'script>');
var root = doc.querySelector("html");
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
var clientWidth = root.getBoundingClientRect().width;
root.style.fontSize = Math.min(100, (clientWidth / 10)) + "px";
};
window.addEventListener(resizeEvt, recalc, false);
return recalc();
})(document);
</script>
</html>
`
);
app.listen(3006, () => {
console.log(`> Local: http://localhost:3006/`);
});
});