使用 esbuild 混合插件为多个文件打包 IIFE 和单个 ESM 包


使用 esbuild 混合插件为多个文件打包 iife 和单个 esm 包

本文介绍如何使用 esbuild 插件和 `define` 特性,为 J*aScript 项目同时生成 IIFE (Immediately Invoked Function Expression) 和 ESM (ECMAScript Module) 两种格式的包。通过自定义插件移除 IIFE 构建中的 imports,并利用 `define` 标志在代码中区分不同构建环境,最终实现代码的按需引入和精简输出,从而优化构建产物的大小和性能。

背景

在开发 J*aScript 库或框架时,通常需要支持多种模块化格式,以满足不同用户的需求。例如,一些用户可能仍然喜欢使用传统的 <script> 标签引入 IIFE 格式的包,而另一些用户则更倾向于使用 ESM 格式的包,以便利用现代 J*aScript 的特性,如 tree shaking。</script>

本文将以 SlickGrid 项目为例,介绍如何使用 esbuild 插件和 define 特性,同时生成 IIFE 和 ESM 两种格式的包,并确保每种格式的包都只包含必要的代码,从而优化构建产物的大小和性能。

解决方案

该解决方案的核心在于使用 esbuild 插件来处理 IIFE 构建中的 imports,并使用 define 特性在代码中区分不同的构建环境。

1. 自定义 esbuild 插件移除 Imports

首先,我们需要创建一个 esbuild 插件,用于在 IIFE 构建中移除所有的 import 语句。这是因为 IIFE 格式的包通常依赖于全局变量,而不是模块导入。

import { build } from 'esbuild';

const removeImportsPlugin= {
    name: 'remove-imports-plugin',
    setup(build) {
      build.onResolve({ filter: /.*/ }, (args) => {
        if (args.kind !== 'entry-point') {
          return { path: args.path + '.js', namespace: 'import-ns' }
        }
      });
      build.onLoad({ filter: /.*/, namespace: 'import-ns' }, () => ({
        contents: `// empty string, do nothing`,
        loader: 'js',
      }));
    }
};

这个插件使用了 onResolve 和 onLoad 钩子。onResolve 钩子拦截所有非入口文件的导入请求,并将其重定向到 import-ns 命名空间。onLoad 钩子则拦截 import-ns 命名空间下的所有文件加载请求,并返回一个空字符串,从而有效地移除了所有的 import 语句。

2. 使用 define 特性区分构建环境

接下来,我们需要使用 esbuild 的 define 特性,在代码中定义一个全局变量,用于区分 IIFE 和 ESM 构建环境。

Jaaz Jaaz

开源的AI设计智能体

Jaaz 216 查看详情 Jaaz
/** build as iife, every file will be bundled separately */
export async function buildIifeFile(file) {
  build({
    entryPoints: [file],
    format: 'iife',
    // add Slick to global only when filename `slick.core.js` is detected
    globalName: /slick.core.js/.test(file) ? 'Slick' : undefined,
    define: { IIFE_ONLY: 'true' },
    outfile: `dist/browser/${file.replace(/.[j|t]s/, '')}.js`,
    plugins: [removeImportsPlugin],
  });
}

// bundle in ESM format into single file index.js
export function buildEsm() {
  build({
    entryPoints: ['index.js'],
    format: 'esm',
    target: 'es2025',
    treeShaking: true,
    define: { IIFE_ONLY: 'false' },
    outdir: `dist/esm`,
  });
}

在 IIFE 构建中,我们将 IIFE_ONLY 定义为 'true',而在 ESM 构建中,我们将 IIFE_ONLY 定义为 'false'。

3. 在代码中使用 IIFE_ONLY 变量

现在,我们可以在代码中使用 IIFE_ONLY 变量来区分不同的构建环境。例如:

// imports will be auto-dropped in iife by custom plugin
import { SlickEvent as SlickEvent_, Utils as Utils_ } from '../slick.core';

// for (iife) load `Slick` methods from global window object, or use imports for (cjs/esm)
const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_;
const Utils = IIFE_ONLY ? Slick.Utils : Utils_;

// ...

// then use it normally in the code...
const options = Utils.extend(true, {}, defaults, options);

在 IIFE 构建中,IIFE_ONLY 为 'true',因此 SlickEvent 和 Utils 将从全局 Slick 对象中获取。而在 ESM 构建中,IIFE_ONLY 为 'false',因此 SlickEvent 和 Utils 将从 import 语句中获取。

示例

以下是一个完整的示例,展示如何使用 esbuild 插件和 define 特性同时生成 IIFE 和 ESM 格式的包:

// esbuild.config.js
import { build } from 'esbuild';

const removeImportsPlugin= {
    name: 'remove-imports-plugin',
    setup(build) {
      build.onResolve({ filter: /.*/ }, (args) => {
        if (args.kind !== 'entry-point') {
          return { path: args.path + '.js', namespace: 'import-ns' }
        }
      });
      build.onLoad({ filter: /.*/, namespace: 'import-ns' }, () => ({
        contents: `// empty string, do nothing`,
        loader: 'js',
      }));
    }
};

/** build as iife, every file will be bundled separately */
export async function buildIifeFile(file) {
  build({
    entryPoints: [file],
    format: 'iife',
    // add Slick to global only when filename `slick.core.js` is detected
    globalName: /slick.core.js/.test(file) ? 'Slick' : undefined,
    define: { IIFE_ONLY: 'true' },
    outfile: `dist/browser/${file.replace(/.[j|t]s/, '')}.js`,
    plugins: [removeImportsPlugin],
  });
}

// bundle in ESM format into single file index.js
export function buildEsm() {
  build({
    entryPoints: ['index.js'],
    format: 'esm',
    target: 'es2025',
    treeShaking: true,
    define: { IIFE_ONLY: 'false' },
    outdir: `dist/esm`,
  });
}

// index.js
// imports will be auto-dropped in iife by custom plugin
import { SlickEvent as SlickEvent_, Utils as Utils_ } from '../slick.core';

// for (iife) load `Slick` methods from global window object, or use imports for (cjs/esm)
const SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_;
const Utils = IIFE_ONLY ? Slick.Utils : Utils_;

// ...

// then use it normally in the code...
const options = Utils.extend(true, {}, defaults, options);

总结

通过使用 esbuild 插件和 define 特性,我们可以轻松地为 J*aScript 项目同时生成 IIFE 和 ESM 两种格式的包,并确保每种格式的包都只包含必要的代码。这可以显著减小构建产物的大小,并提高应用程序的性能。

注意事项:

  • define 特性会将字符串值视为 J*aScript 代码,因此需要确保字符串值的格式正确。
  • 在 IIFE 构建中,需要确保所有的依赖项都已通过 <script> 标签加载到全局环境中。</script>
  • 可以根据实际需求调整插件和 define 特性的配置。

希望本文能够帮助你更好地理解如何使用 esbuild 同时生成 IIFE 和 ESM 格式的包。

以上就是使用 esbuild 混合插件为多个文件打包 IIFE 和单个 ESM 包的详细内容,更多请关注其它相关文章!


# 都只  # 稷山SEO推广  # 罗湖有什么网站推广  # 苏州seo推广网站  # seo优化针对的人群  # 顺德页面seo优化价格  # 咸阳品牌网站建设  # 黔江网站建设费用  # 宜昌本地智能营销推广是什么  # 全网营销外包推广效果  # 新手要多久上手seo  # 中特  # javascript  # 自定义  # 我们可以  # 而在  # 全局变量  # 移除  # 两种  # 如何使用  # 多个  # win  # js  # java 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 优化Asyncio嵌套函数调度:使用生产者-消费者模式实现并发流处理  嘴唇干裂起皮怎么办 唇部护理与预防干裂的方法【详解】  《宝可梦大集结》S4冠军之路开始时间介绍  行者app怎样导出日志  在VS Code中利用AI辅助进行代码迁移  《暗黑破坏神4》国服回归送狂欢礼包 价值6916元  TikTok网页版入口快速访问 TikTok官网账号登录方法  PHP odbc_fetch_array 返回值处理:如何正确访问嵌套数组元素  mysql中如何分析索引使用情况_mysql索引使用分析方法  《随手记》启用语音备注方法  百度浏览器无法安装扩展程序_百度浏览器插件安装失败原因解析  C++ static关键字作用_C++静态成员变量与静态函数  SQLAlchemy 2.0 与 Pydantic 模型类型安全集成指南  海棠书屋官方在线书籍入口 海棠书屋文学作品浏览官网链接  《procreate》绘制渐变效果教程  《环球网校》设置报考省市方法  修复UI元素交互障碍:从“开始”按钮到信息框的平滑过渡实现  传统曲艺莲花落的表演形式是  C++ optional用法详解_C++17处理可能为空的返回值  人教版电子教材在线获取指南  LocoySpider如何批量采集电商商品_LocoySpider电商采集的模板应用  在Spring Boot Thymeleaf中利用布尔属性实现容器的条件显示  《猎聘》筛选猎头岗位方法  视频号视频怎么免费保存到相册?保存到相册需要注意什么?  如何取消数字签名  Coolpad5890 ROM刷机包  猫眼电影app如何设置电影上映提醒_猫眼电影上映提醒设置教程  大众点评了却看不到是怎么回事  Sublime怎么配置YAML文件格式化_Sublime YAML Formatter插件教程  如何在mysql中使用索引提示_mysql索引提示优化方法  漫蛙manwa官网浏览入口_漫蛙漫画网页版访问链接  漫蛙manwa漫画官网链接_漫蛙manwa最新可用网址推荐  《画加》约稿流程  ao3入口镜像地址 ao3镜像入口可靠跳转  使用document.execCommand实现Web文本编辑器加粗/取消加粗  Win10如何关闭操作中心通知 Win10免打扰设置全攻略【清爽】  百度小说看书时如何翻页_百度小说手动翻页与自动翻页设置  百度网盘如何设置上传限额  盲鳗善于分泌黏液猜猜主要用来做什么  汽水音乐官网网页版入口 汽水音乐官网网页版在线入口  芒果TV官网登录入口 芒果TV官方网站登录入口  Win10运行窗口在哪里打开 Win10调出运行命令框快捷键【技巧】  Python中对象引用与链表属性赋值的机制解析  Lar*el Socialite单设备登录策略:实现用户唯一会话管理  《广发易淘金》国债逆回购操作教程  《360浏览器》自动保存账号密码设置方法  抖音号升级企业号怎么改名字?升级企业号有哪些好处?  Golang如何实现HTTP请求重试机制_Golang HTTP请求错误处理策略  PySimpleGUI中实现键盘按键与按钮事件绑定教程  如何在Podman容器中运行Composer_Docker替代品Podman的PHP与Composer容器化实践 

 2025-10-29

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.