esbuild 从入门到放弃

1,132 阅读1分钟

一. 引言

自我介绍:大家好,我是一名前端小白,听闻前端已死,遂记录自己在学习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.效果展示

image.png

image.png

四. 如何使用字体图标库

1.对一些矢量图标图如阿里图标库的文件后缀添加loader

loader: {
      ".scss": "text",
      ".eot": "file",
      ".woff": "file",
      ".ttf": "file",
},
  1. 将图标文件放到项目中

image.png

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">&#xf51c;</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/`);
    });
  });