亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

使用ESBuild搭建TypeScript項目環境

历史上,我一直讨厌处理JavaScript构建工具。多年来,这对我来说似乎是一个令人沮丧且脆弱的过程;以至于我花时间自己开发工具来避免麻烦。我很高兴看到这个生态系统领域似乎终于成熟了。最近,当我花时间重新评估现在的选择时,我感到非常惊喜。

我在五月启动了一个全新的纯JS Web组件项目,使用了原生模块和导入映射,没有转译器或打包工具。这种方式开始新项目非常高效,我强烈推荐这样做。摆脱了工具和库/框架的限制,直接接触原始的Web环境,这能够让你更好地探索项目的最佳架构。

话说回来,前几周我到了一个阶段,开始感受到维护不断增长的代码库,却没有大规模重构和重新设计的支持,让我感到痛苦。我也知道直接部署未打包的JavaScript代码到生产环境是不可能的,这个问题迟早需要处理。最后,还有一些新的JS特性,例如装饰器,我真的很想在我的代码库中使用,但没有编译器是无法实现的。于是到了做决定的时候了。

首先,我花了一些时间将我的项目转换为TypeScript。虽然过程中遇到了一些小挫折,但转换速度很快。我比较顺利地让项目运行了起来。我发现并修复了代码中的几个错误。更重要的是,通过构建之前隐含的类型,我能够更清楚地发现设计上的问题和不一致。

为此,我很感激。

aside:TypeScript 并不是实现这一点的唯一方式。JSDoc 注释也可以完成许多任务。但这不是这篇文章的重点,所以我不会深入探讨为什么我选择了 TypeScript。当你为自己的项目做决定时,请确保评估当前的选项,看看它们是否符合你的项目要求。

随着转换到 TypeScript 完成,我接下来需要处理打包。于是我犹豫地从一个以前的项目中拿出了一个标准的 Webpack TypeScript 配置。大约一周后,我决定这种选择太麻烦了。那个月只用纯模块和 import maps,这种对比特别明显。

寻找构建工具之旅

我对Webpack配置的不满程度显然超过了我对构建工具和配置的一贯厌恶,所以我决定重新审视一下市场。在做出决定前,我需要先理清我的需求。我列了一份我认为简洁且合理的清单,专门针对我的项目:

  • 支持 TypeScript,包括像 Stage 3 装饰器这样的转译功能。
  • 既适用于生产构建也适用于开发过程中的快速迭代,比如构建、监视、启动和重新加载。
  • 配置简单,不需要花费太多时间和精力去编写、维护和更新。
  • 构建时间比 Webpack 更快,并且解决了我在项目中遇到的一些烦人的工作流程问题。
  • 保持尽可能少的依赖项。
  • 是一个稳定且健康的开源项目,有活跃的贡献者和宽松的许可。

尽管我对该项目的高热度保持了一定的警惕,我从一些信任的人那里得到了一些积极的反馈。在评估技术之前,我已经列出了我的需求清单,这为我提供了坚实的初步评估基础。

就这样

一上来我就发现 Vite 不支持我的第一个需求:

  • 支持 TypeScript,以及转译 Stage 3 Decorators。

虽然 Vite 支持 TypeScript,但它只是通过擦除类型,然后打包成普通的 JS。只要有一个简单的插件可以让我选择使用真正的 TypeScript 编译器就好了。没费多大劲儿,我发现 Vite 负责人明确表示他们不仅不支持使用真正的 TypeScript 编译器,还明确表示没有这个计划。好吧,这让我做决定变得很简单。

aside:Vite 是一个极具个性的工具。如果你的需求和 Vite 的理念一致,它会变得非常快捷且易于使用。如果不一致,这可能不是适合你的工具。正如我在其他地方所说 见此处,应该先明确你的需求,再考虑使用什么工具,而不是让工具来限定你的架构和需求。

接下来,我查看了一下Parcel。它似乎满足了我的所有需求。因此,我试着把它设置好。不用详述具体细节,我的项目需要通过script标签使用一些依赖项,并且需要特殊处理。Parcel在这方面似乎有问题。我花了好几小时找插件和尝试自定义设置,希望能找到合适的设置,让构建成功并且运行时也能正常工作。

我放弃了,我决定即使能运行起来,Parcel 不符合我项目中的以下要求:

  • 配置比 Webpack 简单得多,功能相同,不用花费太多精力来编写、维护和更新配置文件。

我对这种状况不太耐烦,也知道不能无休止地花大量时间在这个过程中。所以我决定向前走,看看其他办法。

现在有很多构建选项。我没有足够的时间去尝试所有这些选项。然而,似乎存在一些共同点。许多工具要么基于 Rollup 或 ESBuild,要么受到它们的启发。所以我决定深入了解这两个底层工具。

以前我用过Rollup来构建库,但没用过它来构建应用。于是我再看了看。可惜的是,它没有自带开发服务器。它的网站推荐使用Vite,但我之前已经把它排除了。

那就是ESBuild

我估计你看到这篇帖子的标题就知道我要说什么了 😉 总之,我发现 ESBuild 完全满足了我的所有需求。我很快就让整个项目包括所有特有特性都运行起来了,而且代码量很少,用时也很短。

我也很高兴能使用那种其他打包程序实际上在其基础上进行开发的核心技术栈。我一直喜欢直接操作底层技术。我喜欢这种做法带来的强大和灵活性。

此外,很高兴看到我的node_modules文件夹和package.json文件都非常小巧。这里是我node_modules文件夹中完整的包列表如下所示:

    @esbuild  
    esbuild  
    esbuild-plugin-tsc  
    strip-comments  
    tslib  
    typescript

就这样!这是我完整的package.json依赖列表如下所示:

    "dependencies": {  
      "tslib": "^2.5.2"  
    },  // 依赖
    "devDependencies": {  
      "esbuild": "0.17.19",  
      "esbuild-plugin-tsc": "^0.4.0",  
      "typescript": "^5.0.4"  
    }  // 开发依赖

这比我预期的还要好呢,简直了!🎉

如何为 TypeScript 设置 ESBuild

要使用ESBuild设置一个基本的TypeScript项目,你需要安装这两个工具:[esbuild](https://www.npmjs.com/package/esbuild)[esbuild-plugin-tsc](https://www.npmjs.com/package/esbuild-plugin-tsc)

这将使用npm安装开发依赖项esbuild和esbuild-plugin-tsc。

这个依赖仅在你实际使用官方TypeScript编译器时才需要。否则不需要它。

注意:请参阅上面的我的 "package.json" 文件,以了解这些步骤适用的具体版本号。

安装了这些依赖项之后,我想创建两个可以运行的任务。

  • npm start — 构建并实时监控我的源代码,同时提供我的 index.html 页面,当代码变更时,自动重建并刷新页面。应生成未压缩的源代码和源映射,并且该设置应能很好地配合 VS Code 调试工具使用。
  • npm run build — 构建一个完全压缩打包的源代码版本,准备部署的版本。

这两个命令都需要相同的 ESBuild 核心配置。因此,我创建了一个 settings.js 模块,导出了一个用于生成共享设置的函数。

settings.js

import esbuildPluginTsc from 'esbuild-plugin-tsc';  

// 创建构建设置函数
export function 创建构建设置(options) {  
  return {  
    // 入口点
    entryPoints: ['src/main.ts'],  
    // 输出文件
    outfile: 'www/bundle.js',  
    // 打包
    bundle: true,  
    // 插件
    plugins: [  
      esbuildPluginTsc({  
        // 强制编译
        force: true  
      }),  
    ],  
    // 将传入的选项展开
    ...options  
  };  
}

这个函数接收一个名为 options 的对象,将其扩展到核心设置中,允许调用者添加或覆盖基础设置,如你将看到的。这些共享设置本身相当直接:

  • entryPoints — 这指向了我的应用的主要入口文件,位于 src 文件夹下的 main.ts 文件中。
  • outfile — 这是我希望我的 bundle 生成的位置。我的项目中有一个 www 文件夹,其中包含了 index.html、图片、manifest.json 和其他静态文件。我需要 bundle 与这些文件一起生成。
  • bundle — 请打包我的代码。
  • plugins — ESBuild 提供了许多插件。我只需要确保使用 TypeScript 编译器。为此,我将 [esbuild-plugin-tsc](https://www.npmjs.com/package/esbuild-plugin-tsc) 插件传递给 ESBuild。此插件有许多选项。我只需要配置 force: true,以确保 TypeScript 用于所有内容,这有助于 Stage 3 装饰器的正常工作。

aside:有些人可能担心直接使用 TypeScript 会比较慢。在我的项目中,它的运行速度非常快,几乎可以说是闪电般。它的速度需要大幅度下降,才能接近我在使用 Webpack 时的体验。因此,我认为现在这样做是对这个项目的正确选择。不过我会定期重新评估这样的决定。我建议你也这样做。随着项目的进展,需求也会不断变化,可能会与现有的工具和架构不匹配。这也是为什么最好一开始做出简单且容易调整的决定的原因之一。特别是未来可能会如何变化,你不想因为早期的决定而把自己绑定得太死,从而对你的团队、产品或业务造成损害。

有了这个通用设置助手,我们来看看如何执行build命令。

构建.js

     import * as esbuild from 'esbuild'; // 导入 esbuild 模块
    import { createBuildSettings } from './settings.js'; // 从 settings.js 导入 createBuildSettings 函数
    const settings = createBuildSettings({ minify: true }); // 使用压缩配置创建构建设置
    await esbuild.build(settings); // 使用设置构建项目

那就是全部了。我导入了 esbuild 和我的 settings 辅助模块。我调用辅助模块来创建设置对象,并用我需要告诉 ESBuild 来压缩代码的独特构建设置来增强它。然后,我将设置对象传递给 build 方法,压缩后的 bundle.js 文件就会出现在 www 文件夹里。

好的,那么关于开发者的工作循环呢?这是我怎么实现 serve 任务的。

“serve.js”(文件名)

     import esbuild from 'esbuild';  
    import { createBuildSettings } from './settings.js';  

    const settings = createBuildSettings({   
      sourcemap: true,  
      头部注释: {  
        js: `new EventSource('/esbuild').addEventListener('change', () => location.reload());`, // 监听更改并刷新页面
      }  
    });  

    const ctx = await esbuild.context(settings);  

    await ctx.watch();  

    const { host, port } = await ctx.serve({  
      port: 5500,  
      servedir: '服务目录',  
      fallback: "备用文件"  
    });  

    console.log(`正在 ${host}:${port} 服务。`); // 正在 ${host}:${port} 提供服务

这还有一些额外的内容,但不多,所有内容都清晰明了,都是标准代码。

首先,我创建了一些通用设置,就像我在build任务中做的那样。和之前一样,我需要稍微调整一下。sourcemap选项只是启用了源映射功能。banner选项更有趣。在banner属性中指定的js将会原封不动地注入到包的开头。这段特定的代码通过服务器发送事件连接到ESBuild服务器,以便在监视的资源发生变化时接收通知。当它接收到change消息时,会自动重新加载浏览器。

接下来,我们使用 esbuild 根据我们的配置创建一个名为 context 的对象,该对象将由两个集成的任务共同使用。

  • 通过调用 watch,我们告诉 ESBuild 编译我们的代码并监听变更。
  • 然后通过调用 serve,我们告诉 ESBuild 在 localhost 的 5500 端口上提供我们的 www 目录。我们还提供了一个用于 404 错误的备用页面,这对于 SPA (单页应用) 场景非常有用。

从一个旁白的角度来看:从API设计的视角来看,我喜欢ESBuild将监视与服务这两个关注点明确区分,同时允许通过共享上下文环境将两者整合。

那正是我当时真正需要的一切,但我后来才发现让ESBuild分析打包也很简单。于是我又写了一个脚本。下面是它的样子。

analyze.js

     import * as esbuild from 'esbuild';  // 从'esbuild'导入所有模块
    import fs from 'node:fs';  // 从'node:fs'导入文件系统模块
    import { createBuildSettings } from './settings.js';  // 从'./settings.js'导入createBuildSettings函数

    const settings = createBuildSettings({ minify: true, metafile: true });  // 创建构建设置,启用压缩和元文件
    const result = await esbuild.build(settings);  // 构建设置并等待结果
    const mode = process.env.npm_config_mode;  // 获取npm配置模式

    if (mode === "write") {  // 如果模式是写入
      fs.writeFileSync("build-meta.json", JSON.stringify(result.metafile))  // 将元文件写入到文件
    } else {  
      console.log(await esbuild.analyzeMetafile(result.metafile, {  // 输出元文件分析结果
        verbose: false,  // 设置详细模式为关闭
      }));  
    }

类似于之前的脚本,我们创建一些通用配置。在这个例子中,重要的自定义是 metafile 属性。这告诉 ESBuild 生成一个包含你构建的各种信息的文件,这样你就能获取关于构建的详细信息。当你运行 build 命令时,result 将包含 metafile 属性,你可以根据需求利用它。我编写了一个脚本,通过 --mode=write 参数来判断是否将文件写入磁盘或在控制台显示摘要。如果选择将文件写入磁盘,你可以将其上传到 ESBuild 打包大小分析器,它会为你提供一个打包的可视化展示,并提供交互式钻取功能。

波兰语

我的设置中还有一些与易用性和日常操作流程相关的额外细节。

首先,我一直希望保持项目的有序性。因此,将所有的构建脚本都放在根目录下的 build 文件夹里。然后,我设置了一些脚本以执行这些构建任务。

# 构建脚本命令:
# "build": "node ./build/build.js", # 构建应用
# "start": "node ./build/serve.js", # 启动应用
# "analyze": "node ./build/analyze.js" # 分析应用

"scripts": {  
  "build": "node ./build/build.js",  
  "start": "node ./build/serve.js",  
  "analyze": "node ./build/analyze.js"  
},

接下来,因为我使用的是VS Code作为我的编辑工具,我想要确保能用上它的调试工具。为此目的,我在repo根目录下创建了一个.vscode文件夹,并在此添加了launch.json文件。

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "msedge",
      "request": "type",
      "name": "启动 Edge 浏览 localhost",
      "url": "http://localhost:5500",
      "webRoot": "${workspaceFolder}/www"
    }
  ]
}

需要注意的有几点重要事项:

  • type 有许多选项,但我选择了 msedge,因为它不仅允许我在 VS Code 中直接使用 DOM 检查器,还可以进行正常的 JS/TS 调试。
  • request 需要以一种特殊模式启动浏览器。你可以选择 attach,但我发现这种方式不太稳定,也更费劲。
  • url 包含端口 5500,这是我之前在 serve 任务中设置的端口。
  • webRoot 需要指向我的 www 文件夹,这也是我用来服务的根目录位置。

注意:如果你想用上述设置,还需要安装Microsoft Edge Tools for VS Code

有了这些安排,我的工作流程如下,分为以下几步:

  • 运行 npm start 来构建、监视并启动我的项目。
  • 使用 VSCode 打开浏览器。
  • 在开发过程中,根据需要在 VS Code 中设置断点,检查 TS 代码和 DOM 等。

如果我要生成生产版本,我会运行 npm run build;如果我要简要分析我的包,我会运行 npm run analyze,或者运行 npm run analyze --mode=write 生成元文件并在 ESBuild 网站上查看。

收尾一下

诚然,我的项目较小且简单。每个项目都有自己的特点,需要诚实地评估其特定需求。所以在引入一个打包工具时,我花时间考虑了这些需求。根据我的基本需求缩小了选择范围,最后选择了ESBuild。

最后,我对性能非常满意,同时也对设置的简单性感到满意。最初的动机之一是性能。依赖项很少。如果我的项目需求将来发生变化,我可以通过调整设置并利用许多其他工具所依赖的底层基础设施来得到我需要的东西。如果没有做到,那也没有关系,因为这个解决方案由于其简单性、小投入和与应用程序的解耦,风险很低。在我更新构建时,应用程序本身没有任何改变。

如果你喜欢这篇关于如何为 TypeScript 配置 ESBuild 的文章,你可能还想看看我的 Web Component 工程课程。如果你愿意 订阅我的博客订阅我的 YouTube 频道,或 在 Twitter 上关注我,我非常感激。你的支持对我来说意义重大,它帮助我继续创作类似的内容并分享给更广泛的社区。非常感谢!

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消