likes
comments
collection
share

新一代打包工具esbuild

作者站长头像
站长
· 阅读数 13

了解esbuild

esbuild是什么

esbuild官方描述的作用就是:一个JavaScript的打包和和压缩工具。 esbuild使用golang开发,在打包的速度上非常快,我们熟悉的vite工具在dev模式下就是使用esbuild进行打包。

esbuild的主要特征

  • 在没有缓存的情况也能有极致的性能
  • 支持ES6的Tree shaking
  • 原生支持typescript和jsx打包
  • 支持Source Map
  • 代码压缩
  • 支持定义插件

打包速度比较

esbuild最主要的一个特征就是有极致的性能,那么它到底有多快,参考esbuild官方提供的一张图

新一代打包工具esbuild 可以看到,esbuild的性能跟现在主流的打包工具相比,速度比他们快超过100倍。可见它在性能方面有多可怕。 因为现在主流的打包工具底层上执行还是在js的执行环境中,cpu不能充分地得到使用,所以就会导致执行速度慢。

esbuild使用

了解完esbuild概念,接下来了解一下如何使用esbuild的一些主要概念

API

  • transform transform就是转换的意思,调用这个API能将tsjsx等文件转换为js文件。 支持的文件有:

    export type Loader = 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'json' | 'text' | 'base64' | 'file' | 'dataurl' | 'binary' | 'default';
    

    使用transform 首先我们创建一个测试的TS文件

        // test.ts
        const str: string = 'Hello World';
    

    使用transform转换为js

        // cli
        exbuild ./test.ts --loader=ts // 输出 const str = 'Hello World';
        
        // js api调用
        const esbuild = require('esbuild');
        const fs = require('fs');
        const path = require('path');
        const filePath = path.resolve(__dirname, 'test.ts');
        const code = esbuild.transformSync(fs.readFilesync(filePath), {
            loader: 'ts',
        })
        console.log(code);
        // 输出
        // {
        //  code: 'const str = 'Hello World'',
        //  map: '',
        //  warnings: []
        // }
    

    transform还可以在转换代码的同时进行压缩代码(minify)制定代码的模块类型(format) 等等,部分的的配置如下:

    interface TransformOptions {
      // 源代码的类型
      loader?: Loader;
      // 代码顶部注入代码
      banner?: string;
      // 代码底部注入代码
      footer?: string;
      
      // sourcemap相关配置
      sourcemap?: boolean | 'inline' | 'external' | 'both';
      legalComments?: 'none' | 'inline' | 'eof' | 'linked' | 'external';
      sourceRoot?: string;
      sourcesContent?: boolean;
      
      // 代码压缩相关
      minify?: boolean;
      minifyWhitespace?: boolean;
      minifyIdentifiers?: boolean;
      minifySyntax?: boolean;
      charset?: Charset;
      treeShaking?: TreeShaking;
      
      // jsx相关
      jsx?: 'transform' | 'preserve';
      jsxFactory?: string;
      jsxFragment?: string;
    }
    

    具体的描述可以看这里

  • build build整合了transform后的代码,可以将一个或者多个文件转换并保存为文件。 使用:

        // cli
        esbuild test.ts --outfile=./dist/test.js // { errors: [], warnings: [] }
        
        // js api调用
        const esbuild = require('esbuild');
        const path = require('path');
    
        const result = esbuild.buildSync({
          entryPoints: [path.resolve(__dirname, 'test.ts')],
          outdir: path.resolve(__dirname, 'dist'),
        });
    
        console.log(result); // { errors: [], warnings: [] }
    

    执行完后会生成转换后的代码文件到指定的目录,具体的配置参数可以点击这里

esbuild插件(Plugins)

与其他打包工具一样,esbuild也有plugin,plugin会在build的时候提供一些钩子函数,让你可以在打包的某一个阶段去执行自定义的操作。 plugin提供了四个钩子,按顺序执行分别是:onStartonResolveonLoadonEnd 现在我们就来写一个测试的插件:

const esbuild = require('esbuild');
const path = require('path');

// 测试插件
const testPlugin = {
  name: 'testPlugin',
  setup({ onStart, onResolve, onLoad, onEnd }) {
    onStart(() => {
      console.log('onStart');
    });
    onResolve({ filter: /.*/ }, (msg) => {
      console.log('onResolve', msg);
    });
    onLoad({ filter: /.*/ }, (msg) => {
      console.log('onLoad', msg);
    });
    onEnd((msg) => {
      console.log('onEnd', msg);
    });
  },
};

esbuild.buildSync({
  entryPoints: [path.resolve(__dirname, 'test.ts')],
  outdir: path.resolve(__dirname, 'dist'),
  bundle: true,
  plugins: [testPlugin],
});

执行后返回

新一代打包工具esbuild

实战:利用esbuild打包ts项目

讲完esbuild的大概用法,接下来做一个实战项目。项目中大概的步骤:

  • 1.将typescript项目打包成js文件
  • 2.将打包后的文件放到HTML中运行这个HTML。

首先来写一个插入节点的ts文件test.ts

// test.ts
(function () {
  const app = document.querySelector('#app');
  const div = document.createElement('div');
  div.innerHTML = '<div>Hello World</div>';
  app.appendChild(div);
})();

创建一个html文件

<!DOCTYPE html>
<html>
  <head>
    <title>test html</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="{{scripts}}"></script>
  </body>
</html>

接下来写打包逻辑

// esbuild.js
const esbuild = require('esbuild');
const path = require('path');
const fs = require('fs');
// html文件地址
const HTML_PATH = path.resolve(__dirname, 'index.html');
// 目标地址
const TARGET_PATH = path.resolve(__dirname, 'dist');
// 输出js的地址
const OUTPUT_PATH = './test.js';
/**
 * 自定义插件
 * @type { import('esbuild').Plugin }
 */
const testPlugin = {
  name: 'testPlugin',
  setup({ onEnd }) {
    // 打包结束后执行替换和复制html操作
    onEnd(({ errors }) => {
      console.log(errors);
      if (!errors.length) {
        let data = fs.readFileSync(HTML_PATH, { encoding: 'utf-8' });
        data = data.replace(`{scripts}`, OUTPUT_PATH);
        fs.writeFileSync(path.resolve(TARGET_PATH, 'index.html'), data, {
          encoding: 'utf-8',
        });
      }
    });
  },
};

// 打包主方法
esbuild
  .build({
    entryPoints: [path.resolve(__dirname, 'test.ts')],
    outdir: path.resolve(__dirname, 'dist'),
    bundle: true,
    plugins: [testPlugin],
  })
  .then((msg) => {
    if (msg.length) throw new Error('compile error');
    console.log('compile success');
  });

执行esbuild.js文件

新一代打包工具esbuild

文件已经生成成功,打开html文件看一下有没有执行js 新一代打包工具esbuild

代码成功执行 新一代打包工具esbuild

小结

本文主要介绍了esbuild打包工具。主要介绍了:

  • esbuild的性能比现在主流的打包工具要快得多
  • esbuild的api和用法
  • esbuild如何定义插件
  • 利用esbuild打包一个ts项目

若文章中有不严谨或出错的地方请在评论区域指出~

参考

  1. esbuild