当前位置: 首页 > news >正文

笔记:使用 unbuild 搭建 JavaScript 构建系统笔记

使用 unbuild 搭建 JavaScript 构建系统

jcLee95:https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
邮箱 :291148484@163.com

简介:
本文是笔者阅读分析 elementPlus 项目时记录的。该项目用到了一个完全没有文档和资料的工具 unbuild。

为了搞清楚其功能,在github上看了一下该模块的源代码并记录之。

本文地址https://blog.csdn.net/qq_28550263/article/details/129016838

目 录

1. unbuild 简介与安装

2. unbuild 的用法

  • 2.1 配置文件 build.config.ts
  • 2.2 pacakage.json 与 cli 用法

3. 该模块用到的一些模块

  • 3.1 一款 await 的挂钩系统:hookable

    • 3.1.1 安装
    • 3.1.2 通过直接创建 hookable 实例使用
    • 3.1.3 通过从 Hookable 扩展你的基类使用
    • 3.1.4 Hookable 类的接口解析
  • 3.2 轻量级文件到文件转换器:mkdist

  • 3.2.1 简介与安装

  • 3.2.2 mkdist 的用法

3.3 Node.js 的运行时Typescript 和 ESM 支持:jiti

  • 3.3.1 简介与安装
  • 3.3.2 jiti 的用法

3.4 将字节转换为人类可读的字符串:pretty-bytes

  • 3.4.1 简介与安装
  • 3.4.2 用法

附录


1. unbuild 简介与安装

搭建前端项目时,我们经常需要寻找一些构建工具来辅助我们自动化地进行打包和完成其它工作,如 webpack、rollup、gulp、vite 等等。对于一些功能的需求比较简单的场景,我们用不着使用 webpack 之类的重型构建工具,完全可以考虑使用一些小工具完成。本文介绍的 unbuild 就是这样一个小工具,它是一个强大的基于 rollup 的捆绑器,支持 TypeScript 并生成 commonjs 和 module 格式 + 类型声明。它能够能够自动推断 package.json 中的 build 配置和条目。

你可以通过如下方式安装到项目依赖中:

npm i unbuild -D
# 或
yarn add unbuild -D
# 或
pnpm i unbuild -D

2. unbuild 的用法

2.1 配置文件 build.config.ts

unbuild CLI 基于配置文件 build.config.ts 工作,你应该手动在项目根目录中创建它,以便于执行脚本的时候被 unbuild 所找到。一个该文件的实例为:

import { defineBuildConfig } from 'unbuild'export default defineBuildConfig({// 如果没有提供entries,将从package.json中自动推断出entries: [// 指定源文件入口,默认值为 './src/index''./src/index',// mkdist builder 传输文件到文件,保持原始源结构{builder: 'mkdist',input: './src/package/components/',outDir: './build/components'},],// 指定输出目录,默认为 'dist'outDir: 'build',// 指定是否生成 .d.ts 声明文件declaration: true,
})

其中 defineBuildConfig 传入的对象可以配置以下内容:

配置项类型描述
rootDirstring指定根目录起始位置
entriesBuildEntry[];指定源文件入口,默认值为 './src/index'
cleanboolean输出前是否清空输出目录
declarationboolean指定是否生成 .d.ts 声明文件
outDirstring指定输出目录,默认为 'dist'
stubboolean跳过 stub 的剩余部分
externalsstring[]是否所有依赖项作为外部项添加(dependencies、peerDependencies)
dependenciesstring[]从pkg推断的依赖关系
peerDependenciesstring[]从pkg推断的依赖关系
devDependenciesstring[]从pkg推断的依赖关系
alias{ [find: string]: string;}由 unbuild 传给 rollup 的 alias 配置项
replace{ [find: string]: string;}由 unbuild 传给 rollup 的 replace 配置项
rollupRollupBuildOptions由 unbuild 传给 rollup 的构建选项
hooksPartial<BuildHooks>
presetstring | BuildPreset

2.2 pacakage.json 与 cli 用法

{"main": "./dist/index.cjs","module": "./dist/index.mjs","types": "./dist/index.d.ts","scripts": {"build": "unbuild","dev": "pnpm run stub","stub": "unbuild --stub"},"devDependencies": {"unbuild": "^0.7.4"}
}

3. 该模块用到的一些模块

这个部分是在分析 unbuild 模块源码中用到的一些库。

3.1 一款 await 的挂钩系统:hookable

3.1.1 简介与安装

该模块用于管理注册和调用钩子,你可以通过以下方式进行安装:

npm install hookable
# or
yarn add hookable
# or
pnpm install hookable

3.1.2 通过直接创建 hookable 实例使用

import { createHooks } from 'hookable'// 创建一个 hookable 实例
const hooks = createHooks()// 挂上 'hello'
hooks.hook('hello', () => { console.log('Hello World' )})// 调用 'hello' 钩子
hooks.callHook('hello')

3.1.3 通过从 Hookable 扩展你的基类使用

import { Hookable } from 'hookable'export default class FooLib extends Hookable {constructor() {// 调用父类进行初始化super()// 用自定义 logger 初始化可挂钩// super(consola)}async someFunction() {// 按顺序调用并等待“hook1”挂钩(如果有)await this.callHook('hook1')}
}

在插件中,注册任意钩子:

const lib = new FooLib()// 注册“hook2”的处理程序
lib.hook('hook2', async () => { /* ... */ })// 一次注册多个处理程序
lib.addHooks({hook1: async () => { /* ... */ },hook2: [ /* 也可以是一个数组 */ ]
})

3.1.4 Hookable 类的接口解析

3.2 轻量级文件到文件转换器:mkdist

3.2.1 简介与安装

Bundling 库有时候不是最佳的选择,因为通过捆绑传输丢失现代语法,也让我们丢失原有的文件结构,也有时通过将css提取到全局dist(vue) 而丢失关键css。
即使不使用,依赖项也将总是从 bundle 绑包中导入(第二个捆绑步骤可能会解决这个问题,但这通常不会发生在开发中和有副作用的依赖项中)。

虽然有像 tsc@babel/cli 这样的工具,但它们大多专注于传输文件,而不是保持源代码级别的质量。此外,它们缺乏对处理自定义扩展的支持,如。vue和复制assets

mkdist可以:

  • 复制所有的 assets;
  • 支持 Vue 单文件组件;
  • 通过 esbuild 实现快速和最小的转换;
  • .为 .ts, .js.vue 文件生成 d.ts 类型声明文件

你可以通过以下方式进行安装:

npm install mkdist
# or
yarn add mkdist
# or
pnpm install mkdist

3.2.2 mkdist 的用法

CLI 的语法格式

mkdist [rootDir] [--src=src] [--dist=dist] [--pattern=glob [--pattern=more-glob]] [--format=cjs|esm] [-d|--declaration] [--ext=mjs|js|ts]

3.3 Node.js 的运行时 Typescript 和 ESM 支持:jiti

3.3.1 简介与安装

jiti 是一款Node.js 的运行时 Typescript 和 ESM 支持模块,也就是说它可以让 Nodejs 运行时运行 Typescript 和 ESM 代码,该模块可以:

  • 无缝typescript和ESM语法支持;
  • ESM和CommonJS之间的无缝互操作性;
  • 替换 require 的同步API;
  • 超级苗条和零依赖;
  • 智能语法检测,避免额外的转换;
  • CommonJS缓存集成;
  • 文件系统传输文件硬缓存;
  • V8编译缓存;
  • 自定义解析别名

你可以通过如下之一的方式进行安装:

npm install jiti
# or
yarn add jiti
# or
pnpm install jiti

3.3.2 jiti 的用法

1. 编程用法

const jiti = require("jiti")(__filename);jiti("./path/to/file.ts");

2. 命令行用法

若是全局安装了 jiti ,可以直接使用 jiti 命:

jiti index.ts

若只在当前项目中安装了 jiti ,可用 npx jiti 运行脚本文件

npx jiti index.ts

3.4 将字节转换为人类可读的字符串:pretty-bytes

3.4.1 简介与安装

该模块可用于打包时在终端更好地输出文件大小,可以通过如下方式进行安装:

npm install pretty-bytes
# or
yarn add pretty-bytes
# or
pnpm install pretty-bytes

3.4.2 用法

import prettyBytes from 'pretty-bytes';prettyBytes(1337);
//=> '1.34 kB'prettyBytes(100);
//=> '100 B'// 以位为单位显示
prettyBytes(1337, {bits: true});
//=> '1.34 kbit'// 显示文件大小差异
prettyBytes(42, {signed: true});
//=> '+42 B'// 使用德语语言环境的本地化输出
prettyBytes(1337, {locale: 'de'});
//=> '1,34 kB'

附录

  • BuildEntry
declare type BuildEntry = BaseBuildEntry | RollupBuildEntry | UntypedBuildEntry | MkdistBuildEntry;
interface BaseBuildEntry {builder?: 'untyped' | 'rollup' | 'mkdist';input: string;name?: string;outDir?: string;declaration?: Boolean;
}interface UntypedBuildEntry extends BaseBuildEntry {builder: 'untyped';defaults?: Record<string, any>;
}
interface RollupBuildEntry extends BaseBuildEntry {builder: 'rollup';
}
interface MkdistBuildEntry extends BaseBuildEntry {builder: 'mkdist';format?: 'esm' | 'cjs';ext?: 'cjs' | 'mjs' | 'js' | 'ts';
}
  • RollupBuildOptions
import { RollupReplaceOptions } from '@rollup/plugin-replace';
import { RollupAliasOptions } from '@rollup/plugin-alias';
import { RollupNodeResolveOptions } from '@rollup/plugin-node-resolve';
import { RollupJsonOptions } from '@rollup/plugin-json';
import { Options as Options$1 } from 'rollup-plugin-dts';declare type RollupCommonJSOptions = Parameters<typeof commonjs>[0] & {};interface RollupBuildOptions {emitCJS?: boolean;cjsBridge?: boolean;inlineDependencies?: boolean;replace: RollupReplaceOptions | false;alias: RollupAliasOptions | false;resolve: RollupNodeResolveOptions | false;json: RollupJsonOptions | false;esbuild: Options | false;commonjs: RollupCommonJSOptions | false;dts: Options$1;
}
  • BuildHooks
import { RollupOptions, RollupBuild } from 'rollup';interface BuildHooks {'build:prepare': (ctx: BuildContext) => void | Promise<void>;'build:before': (ctx: BuildContext) => void | Promise<void>;'build:done': (ctx: BuildContext) => void | Promise<void>;'rollup:options': (ctx: BuildContext, options: RollupOptions) => void | Promise<void>;'rollup:build': (ctx: BuildContext, build: RollupBuild) => void | Promise<void>;'rollup:dts:options': (ctx: BuildContext, options: RollupOptions) => void | Promise<void>;'rollup:dts:build': (ctx: BuildContext, build: RollupBuild) => void | Promise<void>;'rollup:done': (ctx: BuildContext) => void | Promise<void>;'mkdist:entries': (ctx: BuildContext, entries: MkdistBuildEntry[]) => void | Promise<void>;'mkdist:entry:options': (ctx: BuildContext, entry: MkdistBuildEntry, options: MkdistOptions) => void | Promise<void>;'mkdist:entry:build': (ctx: BuildContext, entry: MkdistBuildEntry, output: {writtenFiles: string[];}) => void | Promise<void>;'mkdist:done': (ctx: BuildContext) => void | Promise<void>;'untyped:entries': (ctx: BuildContext, entries: UntypedBuildEntry[]) => void | Promise<void>;'untyped:entry:options': (ctx: BuildContext, entry: UntypedBuildEntry, options: any) => void | Promise<void>;'untyped:entry:schema': (ctx: BuildContext, entry: UntypedBuildEntry, schema: Schema) => void | Promise<void>;'untyped:entry:outputs': (ctx: BuildContext, entry: UntypedBuildEntry, outputs: UntypedOutputs) => void | Promise<void>;'untyped:done': (ctx: BuildContext) => void | Promise<void>;
}
interface BuildContext {options: BuildOptions;pkg: PackageJson;buildEntries: {path: string;bytes?: number;exports?: string[];chunks?: string[];}[];usedImports: Set<string>;hooks: Hookable<BuildHooks>;
}
  • BuildPreset
declare type BuildPreset = BuildConfig | (() => BuildConfig);
interface BuildConfig extends DeepPartial<Omit<BuildOptions, 'entries'>> {entries?: (BuildEntry | string)[];preset?: string | BuildPreset;hooks?: Partial<BuildHooks>;
}

相关文章:

笔记:使用 unbuild 搭建 JavaScript 构建系统笔记

使用 unbuild 搭建 JavaScript 构建系统jcLee95&#xff1a;https://blog.csdn.net/qq_28550263?spm1001.2101.3001.5343 邮箱 &#xff1a;291148484163.com 简介&#xff1a; 本文是笔者阅读分析 elementPlus 项目时记录的。该项目用到了一个完全没有文档和资料的工具 unbu…...

【SpringBoot3.0源码】启动流程源码解析 •下

文章目录初始化DefaultBootstrapContext开启Headless模式获取监听器并启动封装命令行参数准备环境打印Banner创建上下文容器预初始化上下文容器刷新Spring容器打印启动时间发布事件执行特定的run方法上一篇《【SpringBoot3.0源码】启动流程源码解析 • 上》&#xff0c;主要讲解…...

QT(56)-动态链接库-windows-导出变量-导出类

1.导出变量 1.1不使用_declspec(dllimport) _declspec(dllexport) 使用_declspec(dllimport) _declspec(dllexport) 1.2win32 mydllwin32 myexe 1.3win32 mydllqt myexe 2.导出类 使用_declspec(dllimport) _declspec(dllexport) 2.1不用关键…...

TCP传输文件

传输文件和传输信息的区别&#xff1a; 传输信息&#xff0c;只是一条数据&#xff0c;传输文件是多条数据传输信息传输过去一般都会显示&#xff0c;传输文件一般不会显示&#xff0c;一般只是存放在文件中传输文件需要传输&#xff0c;文件大小和文件名称&#xff08;不然不知…...

vue3:加载本地图片等静态资源

背景 在我们用 vue2 webpack 的时候&#xff0c;加载图片资源是这样用的&#xff1a; <img :src"require(/assets/test.png)" />这样打包后就会触发 file-loader 打包图片资源&#xff0c;在 dist 文件夹中就可以看到这个图片&#xff08;如果图片较小会打包…...

工作记录------数据库group_concat函数长度问题

工作记录------group_concat函数长度问题 背景&#xff1a;页面在数据展示时&#xff0c;报错&#xff0c;错误显示&#xff1a;String index out of range: -1 异常信息 java.lang.StringIndexOutOfBoundsException: String index out of range: -1at java.lang.String.sub…...

Python基础语法

1 编程环境 1.1 编译环境 pycharmpython/anaconda 1.2 环境设置 File -> settings -> Project interpreter -> 1.3 Hello world 2 条件判断 2.1 例题 【题1】输入一个年份&#xff0c;判断是否是闰年 ①能被4整除&#xff0c;但不能被100整除; ②能被400整…...

windows环境下安装Nginx及常用操作命令

windows环境下安装Nginx及常用操作命令nginx基本概述基本用途nginx安装nginx基本概述 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器。基本用途 nginx是一个轻量级高并发服务器&#xff0c;而tomcat并不是。nginx一般被用来做反向代理&#xff0c;将请求转发到应用…...

python excel数据处理?

前段时间做了个小项目&#xff0c;帮个海洋系的教授做了个数据处理的软件。基本的功能很简单&#xff0c;就是对Excel里面的一些数据进行过滤&#xff0c;统计&#xff0c;对多个表的内容进行合并等。之前没有处理Excel数据的经验&#xff0c;甚至于自己都很少用到Excel。记得《…...

Hudi-集成Flink

文章目录集成Flink环境准备sql-client方式启动sql-client插入数据查询数据更新数据流式插入code 方式环境准备代码类型映射核心参数设置去重参数并发参数压缩参数文件大小Hadoop参数内存优化读取方式流读&#xff08;Streaming Query&#xff09;增量读取&#xff08;Increment…...

重新认识 React Hooks useContext

通常来说,React 数据的传递方式都是一层一层把资料 props 传到子层的 就算第二层(Function Component)、第三层(Button Group Compontn) 根本没有用到这个资料,但是为了传到最底层(button) ,每一层还是必须要传props // App.js const App = () => {const [dark, setDark…...

数据库(2)--加深对统计查询的理解,熟练使用聚合函数

一、内容要求 利用sql建立学生信息数据库&#xff0c;并定义以下基本表&#xff1a; 学生&#xff08;学号&#xff0c;年龄&#xff0c;性别&#xff0c;系号&#xff09; 课程&#xff08;课号&#xff0c;课名&#xff0c;学分&#xff0c;学时&#xff09; 选课&#xff0…...

stm32f407探索者开发板(十五)——NVIC中断优先级管理

文章目录零、前言一、NVIC中断优先级分组1.1 中断的管理方法1.2 抢占优先级&相应优先级的区别1.3 举例1.4 特别说明1.5 中断优先级分组函数二、NVIC中断优先级设置2.1 中断设置相关寄存器2.2 中断设置优先级2.2.1 中断优先级控制的寄存器组 IP[240]2.2.2 中断使能寄存器组 …...

【Azure 架构师学习笔记】-Azure Logic Apps(6)- Logic Apps调用ADF

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Logic Apps】系列。 接上文【Azure 架构师学习笔记】-Azure Logic Apps&#xff08;5&#xff09;- 标准和使用量类型的区别 前言 Logic Apps 和 ADF 的搭配使用是常见的组合&#xff0c;它们可以互相弥补各自的不足和…...

python随机获取列表中某一元素

1、利用Python中的random模块中的choice方法 random.choice()可以从任何序列&#xff0c;比如list列表中&#xff0c;选取一个随机的元素返回&#xff0c;可以用于字符串、列表、元组等。 import random arr[1,2,3,4,5,6] print(random.choice(arr))2、利用Python中的random模…...

Nacos微服务笔记

Nacos安装Nacos 的 Github&#xff08;Tags alibaba/nacos GitHub&#xff09;下载我们所需的 Nacos 版本&#xff0c;可以选择 windows 或者 Linux。 进入官网&#xff0c;选择合适版本&#xff0c;tar.gz为linux版本&#xff0c;zip为windows版本。下载并解压 nacos-server…...

MAC文件误删怎么办?mac数据恢复,亲测很好用的方法

电脑文件误删&#xff0c;应该很多人都经历过。之前分享了很多关于Windows电脑文件误删如何恢复的方法&#xff0c;那么MAC电脑文件误删该怎么办&#xff1f;有什么好方法可以使得mac数据恢复回来吗&#xff1f;下面就给大家分享一些亲测好用的方法&#xff01; 一、MAC电脑的文…...

机械革命z2黑苹果改造计划第二番-MacOS实用软件渗透工具

机械革命z2黑苹果改造计划第二番-实用软件 Mac实用工具 这是旧电脑改造计划的第二篇&#xff0c;就是安装一些常用软件和一些渗透测试工具&#xff0c;武装灵魂成为真正的生产力工具 首先推荐一个网站&#xff0c;www.mactools.app&#xff0c;这个软件里边有大多数常用的软…...

【LeetCode】每日一题(4)

目录 题目&#xff1a;1124. 表现良好的最长时间段 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;1124. 表现良好的最长时间…...

Linux内核移植:内核的启动过程分析、启动配置与rootfs必要文件

Linux内核移植&#xff1a;内核的启动过程、启动配置与rootfs必要文件一、启动过程二、启动配置&#xff08;一&#xff09;SysV初始化&#xff08;二&#xff09;systemd初始化三、rootfs中的启动配置文件1、inittab2、/etc/init.d/rcS 脚本3、fstab4、profile 文件5、其他文件…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...