Esmx
简介
Esmx 是一个基于 Rspack 的高性能 Web 应用框架,提供了完整的应用生命周期管理、静态资源处理和服务端渲染能力。
类型定义
BuildSsrTarget
1type BuildSsrTarget = 'client' | 'server'
应用程序运行时环境类型:
client
: 运行在浏览器环境,支持 DOM 操作和浏览器 API
server
: 运行在 Node.js 环境,支持文件系统和服务器端功能
ImportMap
1type ImportMap = {
2 imports?: SpecifierMap
3 scopes?: ScopesMap
4}
ES 模块导入映射类型。
SpecifierMap
1type SpecifierMap = Record<string, string>
模块标识符映射类型,用于定义模块导入路径的映射关系。
ScopesMap
1type ScopesMap = Record<string, SpecifierMap>
作用域映射类型,用于定义特定作用域下的模块导入映射关系。
COMMAND
1enum COMMAND {
2 dev = 'dev',
3 build = 'build',
4 preview = 'preview',
5 start = 'start'
6}
命令类型枚举:
dev
: 开发环境命令,启动开发服务器并支持热更新
build
: 构建命令,生成生产环境的构建产物
preview
: 预览命令,启动本地预览服务器
start
: 启动命令,运行生产环境服务器
实例选项
定义 Esmx 框架的核心配置选项。
1interface EsmxOptions {
2 root?: string
3 isProd?: boolean
4 basePathPlaceholder?: string | false
5 modules?: ModuleConfig
6 packs?: PackConfig
7 devApp?: (esmx: Esmx) => Promise<App>
8 server?: (esmx: Esmx) => Promise<void>
9 postBuild?: (esmx: Esmx) => Promise<void>
10}
root
- 类型:
string
- 默认值:
process.cwd()
项目根目录路径。可以是绝对路径或相对路径,相对路径基于当前工作目录解析。
isProd
- 类型:
boolean
- 默认值:
process.env.NODE_ENV === 'production'
环境标识。
basePathPlaceholder
- 类型:
string | false
- 默认值:
'[[[___GEZ_DYNAMIC_BASE___]]]'
基础路径占位符配置。用于运行时动态替换资源的基础路径。设置为 false
可以禁用此功能。
modules
模块配置选项。用于配置项目的模块解析规则,包括模块别名、外部依赖等配置。
packs
打包配置选项。用于将构建产物打包成标准的 npm .tgz 格式软件包。
devApp
- 类型:
(esmx: Esmx) => Promise<App>
开发环境应用创建函数。仅在开发环境中使用,用于创建开发服务器的应用实例。
entry.node.ts
1export default {
2 async devApp(esmx) {
3 return import('@esmx/rspack').then((m) =>
4 m.createRspackHtmlApp(esmx, {
5 config(context) {
6 // 自定义 Rspack 配置
7 }
8 })
9 )
10 }
11}
server
- 类型:
(esmx: Esmx) => Promise<void>
服务器启动配置函数。用于配置和启动 HTTP 服务器,在开发环境和生产环境中都可使用。
entry.node.ts
1export default {
2 async server(esmx) {
3 const server = http.createServer((req, res) => {
4 esmx.middleware(req, res, async () => {
5 const render = await esmx.render({
6 params: { url: req.url }
7 });
8 res.end(render.html);
9 });
10 });
11
12 server.listen(3000);
13 }
14}
postBuild
- 类型:
(esmx: Esmx) => Promise<void>
构建后置处理函数。在项目构建完成后执行,可用于:
- 执行额外的资源处理
- 部署操作
- 生成静态文件
- 发送构建通知
实例属性
name
当前模块的名称,来源于模块配置。
varName
基于模块名生成的合法 JavaScript 变量名。
root
项目根目录的绝对路径。如果配置的 root
为相对路径,则基于当前工作目录解析。
isProd
判断当前是否为生产环境。优先使用配置项中的 isProd
,若未配置则根据 process.env.NODE_ENV
判断。
basePath
- 类型:
string
- 只读:
true
- 抛出:
NotReadyError
- 框架未初始化时
获取以斜杠开头和结尾的模块基础路径。返回格式为 /${name}/
,其中 name 来自模块配置。
basePathPlaceholder
获取用于运行时动态替换的基础路径占位符。可通过配置禁用。
middleware
获取静态资源处理中间件。根据环境提供不同实现:
- 开发环境:支持源码实时编译、热更新
- 生产环境:支持静态资源的长期缓存
1const server = http.createServer((req, res) => {
2 esmx.middleware(req, res, async () => {
3 const rc = await esmx.render({ url: req.url });
4 res.end(rc.html);
5 });
6});
render
- 类型:
(options?: RenderContextOptions) => Promise<RenderContext>
- 只读:
true
获取服务端渲染函数。根据环境提供不同实现:
- 开发环境:支持热更新和实时预览
- 生产环境:提供优化的渲染性能
1// 基本用法
2const rc = await esmx.render({
3 params: { url: req.url }
4});
5
6// 高级配置
7const rc = await esmx.render({
8 base: '', // 基础路径
9 importmapMode: 'inline', // 导入映射模式
10 entryName: 'default', // 渲染入口
11 params: {
12 url: req.url,
13 state: { user: 'admin' } // 状态数据
14 }
15});
COMMAND
- 类型:
typeof COMMAND
- 只读:
true
获取命令枚举类型定义。
moduleConfig
- 类型:
ParsedModuleConfig
- 只读:
true
- 抛出:
NotReadyError
- 框架未初始化时
获取当前模块的完整配置信息,包括模块解析规则、别名配置等。
packConfig
- 类型:
ParsedPackConfig
- 只读:
true
- 抛出:
NotReadyError
- 框架未初始化时
获取当前模块的打包相关配置,包括输出路径、package.json 处理等。
实例方法
constructor()
- 参数:
options?: EsmxOptions
- 框架配置选项
- 返回值:
Esmx
创建 Esmx 框架实例。
1const esmx = new Esmx({
2 root: './src',
3 isProd: process.env.NODE_ENV === 'production'
4});
init()
- 参数:
command: COMMAND
- 返回值:
Promise<boolean>
- 抛出:
Error
: 重复初始化时
NotReadyError
: 访问未初始化实例时
初始化 Esmx 框架实例。执行以下核心初始化流程:
- 解析项目配置(package.json、模块配置、打包配置等)
- 创建应用实例(开发环境或生产环境)
- 根据命令执行相应的生命周期方法
注意
- 重复初始化时会抛出错误
- 访问未初始化的实例时会抛出
NotReadyError
1const esmx = new Esmx({
2 root: './src',
3 isProd: process.env.NODE_ENV === 'production'
4});
5
6await esmx.init(COMMAND.dev);
destroy()
销毁 Esmx 框架实例,执行资源清理和连接关闭等操作。主要用于:
1process.once('SIGTERM', async () => {
2 await esmx.destroy();
3 process.exit(0);
4});
build()
执行应用程序的构建流程,包括:
- 编译源代码
- 生成生产环境的构建产物
- 优化和压缩代码
- 生成资源清单
注意
在框架实例未初始化时调用会抛出 NotReadyError
entry.node.ts
1export default {
2 async postBuild(esmx) {
3 await esmx.build();
4 // 构建完成后生成静态 HTML
5 const render = await esmx.render({
6 params: { url: '/' }
7 });
8 esmx.writeSync(
9 esmx.resolvePath('dist/client', 'index.html'),
10 render.html
11 );
12 }
13}
server()
- 返回值:
Promise<void>
- 抛出:
NotReadyError
- 框架未初始化时
启动 HTTP 服务器和配置服务器实例。在以下生命周期中被调用:
- 开发环境(dev):启动开发服务器,提供热更新
- 生产环境(start):启动生产服务器,提供生产级性能
entry.node.ts
1export default {
2 async server(esmx) {
3 const server = http.createServer((req, res) => {
4 // 处理静态资源
5 esmx.middleware(req, res, async () => {
6 // 服务端渲染
7 const render = await esmx.render({
8 params: { url: req.url }
9 });
10 res.end(render.html);
11 });
12 });
13
14 server.listen(3000, () => {
15 console.log('Server running at http://localhost:3000');
16 });
17 }
18}
postBuild()
执行构建后的处理逻辑,用于:
- 生成静态 HTML 文件
- 处理构建产物
- 执行部署任务
- 发送构建通知
entry.node.ts
1export default {
2 async postBuild(esmx) {
3 // 生成多个页面的静态 HTML
4 const pages = ['/', '/about', '/404'];
5
6 for (const url of pages) {
7 const render = await esmx.render({
8 params: { url }
9 });
10
11 await esmx.write(
12 esmx.resolvePath('dist/client', url.substring(1), 'index.html'),
13 render.html
14 );
15 }
16 }
17}
resolvePath
解析项目路径,将相对路径转换为绝对路径。
-
参数:
projectPath: ProjectPath
- 项目路径类型
...args: string[]
- 路径片段
-
返回值: string
- 解析后的绝对路径
-
示例:
1// 解析静态资源路径
2const htmlPath = esmx.resolvePath('dist/client', 'index.html');
writeSync()
同步写入文件内容。
-
参数:
filepath
: string
- 文件的绝对路径
data
: any
- 要写入的数据,可以是字符串、Buffer 或对象
-
返回值: boolean
- 写入是否成功
-
示例:
src/entry.node.ts
1async postBuild(esmx) {
2 const htmlPath = esmx.resolvePath('dist/client', 'index.html');
3 const success = await esmx.write(htmlPath, '<html>...</html>');
4}
readJsonSync()
同步读取并解析 JSON 文件。
src/entry.node.ts
1async server(esmx) {
2 const manifest = esmx.readJsonSync(esmx.resolvePath('dist/client', 'manifest.json'));
3 // 使用 manifest 对象
4}
readJson()
异步读取并解析 JSON 文件。
src/entry.node.ts
1async server(esmx) {
2 const manifest = await esmx.readJson(esmx.resolvePath('dist/client', 'manifest.json'));
3 // 使用 manifest 对象
4}
getManifestList()
获取构建清单列表。
该方法用于获取指定目标环境的构建清单列表,包含以下功能:
-
缓存管理
- 使用内部缓存机制避免重复加载
- 返回不可变的清单列表
-
环境适配
- 支持客户端和服务端两种环境
- 根据目标环境返回对应的清单信息
-
模块映射
src/entry.node.ts
1async server(esmx) {
2 // 获取客户端构建清单
3 const manifests = await esmx.getManifestList('client');
4
5 // 查找特定模块的构建信息
6 const appModule = manifests.find(m => m.name === 'my-app');
7 if (appModule) {
8 console.log('App exports:', appModule.exports);
9 console.log('App chunks:', appModule.chunks);
10 }
11}
getImportMap()
获取导入映射对象。
该方法用于生成 ES 模块导入映射(Import Map),具有以下特点:
-
模块解析
- 基于构建清单生成模块映射
- 支持客户端和服务端两种环境
- 自动处理模块路径解析
-
缓存优化
-
路径处理
src/entry.node.ts
1async server(esmx) {
2 // 获取客户端导入映射
3 const importmap = await esmx.getImportMap('client');
4
5 // 自定义 HTML 模板
6 const html = `
7 <!DOCTYPE html>
8 <html>
9 <head>
10 <script type="importmap">
11 ${JSON.stringify(importmap)}
12 </script>
13 </head>
14 <body>
15 <!-- 页面内容 -->
16 </body>
17 </html>
18 `;
19}
getImportMapClientInfo()
获取客户端导入映射信息。
该方法用于生成客户端环境的导入映射代码,支持两种模式:
-
内联模式 (inline)
- 将导入映射直接内联到 HTML 中
- 减少额外的网络请求
- 适合导入映射较小的场景
-
JS 文件模式 (js)
- 生成独立的 JS 文件
- 支持浏览器缓存
- 适合导入映射较大的场景
核心功能:
-
自动处理动态基础路径
-
支持模块路径运行时替换
-
优化缓存策略
-
确保模块加载顺序
-
示例:
src/entry.node.ts
1async server(esmx) {
2 const server = express();
3 server.use(esmx.middleware);
4
5 server.get('*', async (req, res) => {
6 // 使用 JS 文件模式
7 const result = await esmx.render({
8 importmapMode: 'js',
9 params: { url: req.url }
10 });
11 res.send(result.html);
12 });
13
14 // 或者使用内联模式
15 server.get('/inline', async (req, res) => {
16 const result = await esmx.render({
17 importmapMode: 'inline',
18 params: { url: req.url }
19 });
20 res.send(result.html);
21 });
22}
getStaticImportPaths()
获取模块的静态导入路径列表。
1// 获取客户端入口模块的静态导入路径
2const paths = await esmx.getStaticImportPaths(
3 'client',
4 `your-app-name/src/entry.client`
5);