众所周知,Typst Universe 是 typst 生态中的三方包 registry。今天,向大家介绍新一代的 typst 包管理和三方包仓库:NPM Universe。顾名思义,就是使用一个名叫「npm」的命令行工具的 Typst Universe 替代品。
NPM Universe 如此重要,甚至被许多运行时捆绑。例如,在你的包管理器上安装 nodejs
,即可获取一份 npm
的副本。
pacman -S nodejs # Arch Linux
brew install nodejs # macOS
scoop install nodejs # Windows
npm -v
10.9.2
当然,只有一种实现的标准并不健康。你也可以使用速度更快的 pnpm
作为替代品:
pacman -S pnpm # Arch Linux
brew install pnpm # macOS
scoop install pnpm # Windows
npm install -g pnpm # Already installed npm
pnpm -v
10.11.0
与以往的简约风格不同,我们开创性地引入了项目的概念,这有助于我们确定我们的 typst 文稿的依赖版本,以及定义常用的配置。执行下面的命令后,会在当前目录生成一个 package.json
文件。
npm init
NPM Universe 和 Typst Universe 一样,提供了一个 社区仓库的入口,用户可以在这里检索和查阅。

为了维护各个依赖的版本信息,现在我们不再需要记住特定的版本号,而是直接使用 npm install
就可以安装最新版本了。比如,你可以安装我写的 sigfig
包来处理不确定度。
npm install typst-sigfig
与导入 Typst Universe 的 @preview
类似,我们还需要一个特定的前缀:node_modules
。这是 NPM Universe 开创性的「节点模块」架构,每个 typst 包是一个单独的文件夹。
// Pre
// #import "@preview/sigfig:0.1.0": *
// Post
#import "node_modules/typst-sigfig/sigfig.typ": *
之所以叫作 Universe,实际上是因为这个包管理器将 typst 包存储在 node_modules 中。互联网上流传了这样一张图片,说明了 typst 生态的繁荣:

此外,NPM Universe 无需经过繁琐的审核流程,init
好之后,几分钟内即可上传你的代码:
npm publish # 初次使用需要注册账号
NPM Universe 还支持命名空间,这意味着当 typst 升级时,你可以自己将 fork 发版,不必苦苦等待作者适配发版,或者让删掉 styles
的库源码污染你的 git 历史。

更棒的是,NPM Universe 甚至还支持查看 typst 包的源码,还提供完善的代码高亮。这是上一代 Typst Universe 都没做到的功能!

如果你稍加设置,甚至可以在 README 中展示 typst 片段的渲染结果!
{
...,
"scripts": {
...,
"pub": "typst compile --features html --format html README.typ README.md && npm publish"
}
}
当然,NPM Universe 不仅改善了 typst 生态的体验,还意外惠及了前端生态。NPM Universe 慷慨地允许前端开发者分享 Typst 的技术红利——如果你也在使用 astro-typst,可以直接在 .astro 或 .mdx 文件中导入来自 NPM Universe 的包。就以 astro-typst 中的示例来说:
import Simple from "node_modules/astro-typst/src/pages/simp.typ?svg"
<Simple />
NPM Universe 不仅向我们展现了开源软件千帆竞发、共建共享的繁荣与崛起,更体现了其海纳百川、兼容并蓄的自由与开放。跨语言的互操作不再是梦想——最后,谨此献上 NPM Universe 的赞歌:
#import "@preview/jogs:0.2.4": *
#set text(font: "Sart Sans", weight: 300)
#let lib = "let global = {}, setTimeout = (f, _) => {}; " + read("node_modules/echarts/dist/echarts.min.js")
#let code = ```js
const option = {
textStyle: { fontFamily: "Sart Sans" },
title: {
left: "center",
text: "Typst & 前端已经崛起了,这人还没收到通知吗?",
},
tooltip: { trigger: "axis" },
legend: {
data: ["typst/typst", "withastro/astro"],
top: "bottom",
},
xAxis: {
type: "time",
axisLabel: {
formatter: (value) => echarts.format.formatTime("yyyy-MM", value),
},
},
yAxis: {
type: "value",
name: "Star Count",
},
series: [
{
name: "typst/typst",
type: "line",
smooth: true,
itemStyle: {
color: "rgb(0, 119, 255)",
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgb(0, 191, 255)",
},
{
offset: 1,
color: "rgb(0, 119, 255)",
},
]),
},
data: [
[1679421679000, 0],
[1679525567000, 5280],
[1679672355000, 7950],
[1679931973000, 10620],
[1680520762000, 13290],
[1682716282000, 15960],
[1689665289000, 18630],
[1698574915000, 21270],
[1704566769000, 23940],
[1711434638000, 26610],
[1720157331000, 29280],
[1725329624000, 31950],
[1731535220000, 34620],
[1739888574000, 37290],
[1746624740000, 39960],
[1751012293000, 43295],
],
},
{
name: "withastro/astro",
type: "line",
smooth: true,
itemStyle: {
color: "rgb(255, 70, 131)",
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgb(255, 158, 68)",
},
{
offset: 1,
color: "rgb(255, 70, 131)",
},
]),
},
data: [
[1627474805000, 5280],
[1639346595000, 7950],
[1650301136000, 10620],
[1660134580000, 13290],
[1660937362000, 15960],
[1663527602000, 18630],
[1668506551000, 21270],
[1674623974000, 23940],
[1678214898000, 26610],
[1685431037000, 29280],
[1693493029000, 31950],
[1697513567000, 34620],
[1704893954000, 37290],
[1710336916000, 39960],
[1751012349000, 51919],
],
},
],
};
function generateSVG() {
const chart = echarts.init(null, null, {
renderer: "svg",
ssr: true,
width: 400,
height: 300,
});
chart.setOption(option);
const svg = chart.renderToSVGString();
chart.dispose();
return svg;
}
```
#let result = eval-js(lib + code.text + "\ngenerateSVG()")
#image(bytes(result))
版权许可
- 本作品 采用 知识共享 署名—非商业性使用 4.0 国际许可协议(CC BY-NC 4.0 International)许可,阁下可自由地共享(复制、发行) 和演绎(修改、转换或二次创作) 这一作品,唯须遵守许可协议条款。
cscnk52
Windows 10 Firefox 140