Repository navigation
Releases
v0.2.0-beta.0
The first beta: measured and gated. The benchmark suite has 15 workloads with warm-rebuild, development server and type-check
measurements, CI fails on a regression in output size or peak memory, and the corpus has 60 projects.
Added
- The benchmark (rathkit/pack-bench, figures in docs/benchmarks.md) has
15 workloads (Preact, Vue, Solid and Svelte apps, a monorepo-style TypeScript app, date-fns, Zod and D3 beside the original seven)
and times warm rebuilds in each tool's watch mode, development server start and HMR, and build plus type check for the
TypeScript workloads. Pack took the least memory in all 45 build cases and less time than every tool but esbuild and Parcel 3, which
were faster in 3 cases each. In watch mode a Pack rebuild is not the fastest, and HMR notices a change in 85 to 318 ms because it
polls; both are listed as gaps. There is no type-check figure for Pack, which has no checker yet. Against the previous published run, Pack's medians on the seven original workloads moved by -3% to +12% with
identical output and memory, and Pack is still ahead of esbuild in each of them. - The corpus grew from 24 to 60 pinned projects (
corpus/projects.json): more libraries (unjs, pmndrs, nanostores, chalk, d3,
preact and others), and Vue, Solid, Preact, React and Svelte apps, among them Vue apps with UnoCSS and Sass, Redux and
Material UI templates, and folders of larger repositories. All 60 build, and the apps load in a browser without errors. - Sass finds a package by its name, as Vite does:
@use 'element-plus/theme-chalk/src/index.scss'is looked for in the
node_modulesfolders above the file. A leading~works too. - CI checks the output size and the peak memory of the bundler against a stored baseline (
tests/baseline.json,tools/check-baseline.mjs):
five workloads built plain, minified and minified with a source map; a figure that grows past its tolerance fails the build. Time is
checked by the maintainer before a release (docs/RELEASING.md).
Fixed
export default function() {}(no space afterfunction) in a module that another module imports by name was written as
functioncluster_default () {}, which does not parse. Found building d3-hierarchy.- A Vite configuration that reads
__dirname,__filenameorrequireat load time (as most written for CommonJS do) is
bundled with their values instead of failing with "is not defined in ES module scope". Found building vitesse-lite. - The style block of a single-file component (
App.vue?vue&type=style&index=0&lang.scss) is compiled as Sass, Less or
Stylus by the language its query names, not left as source for the style sheet reader.
v0.1.0-alpha.2
Every npm package and the crate are now listed, with the binaries, in the signed SHA256SUMS of the release, and the npm and
crates jobs of the workflow stop unless what they publish matches it; tools/approve-release.mjs makes the same check before the
owner approves (docs/RELEASING.md, docs/verifying.md).
Added
--dtsand--dts-dirwork with TypeScript 7, which has no JavaScript API: its command line writes the declarations.--dts-bundle
still needs TypeScript 5 or 6 and says so.- The browser checks of the repository (the development server and
--hmrwith React, Vue and Svelte, and module federation) run in Firefox and
WebKit as well as Chromium (BROWSER=firefoxorwebkit); the three are driven with no dependency of ours and are run in CI on Ubuntu 24.04. - Less, Sass (
sass-embeddedorsass) and Stylus files are compiled when the compiler is installed in the project, as Vite does,
and read as style sheets (including.module.scss). This applies to builds that use a configuration file, since the
compilers run in the plugin host; a project that lists its own plugin for one of these languages keeps it.
Fixed
- Watch mode finds a file that changed while the build that first saw it was running.
- The self-signed certificate of the HTTPS dev server has a serial number that is a valid DER integer.
- On Windows, a path is written as a file URL with
--original-paths, a name that starts with a slash stays rooted, and the
in-memory modules of a build, the metafile and module federation compare paths without the platform's separators. - In a page build, the dev server and
--platform-browser,process.env.NODE_ENVis a constant (productionfor a build,development
for the server, or the environment'sNODE_ENV;--definewins), as in Vite. Those outputs also no longer start with
import ... from "node:module"or"node:url"(therequireand__dirnameshims), which a browser cannot load and which
stopped every chunk of a page that had any CommonJS code in it. - In a page build, a Node built-in (
crypto,fs,node:path, ...) that no plugin supplies is an empty module, as in Vite, so a library that
reaches forcryptowhen it is there no longer leavesimport "crypto"in a script a browser cannot load. A program for Node keeps the import. - In a page build (and
--platform-browser), thebrowsercondition ofexports, thebrowserfield as an entry, and the object form of
a package'sbrowserfield ("./lib/node.js": "./lib/web.js","fs": false) are followed, as in Vite; axios and many other packages need it
to keep their Node code out of a page. - When the build is split into chunks, a member read through a namespace import (
import * as N from "pkg"; N.make()) whose declaration is
behind files of re-exports (export * from) is kept; it was left out of every chunk (naive-ui'screateDiscreteApi). - Code written without semicolons: a name that the bundle writes as
(0, x.y)or(x)(a CommonJS import) no longer joins the line before it
as a call (const a = f()followed by a lineuseEffect(...)becamef()(0, ...)); the;the author left out is written. - A dynamic import with a variable may start with an alias (
import(\@/layouts/${name}/index.vue`), as Vue'sdefineAsyncComponentis usually written), and the variable may be in the name of a folder (${name}/index.vue`), not only in the last name; the extension must still be written out. - A build driven by a
webpack.config.*orrspack.config.*names the chunk of the default entrymain.js, as webpack and Rspack do, not
bundle.js, so a page template that says<script src="./main.js">finds it. - Rspack's
HtmlRspackPlugin(from@rspack/core) works: the compiler takes Rspack's built-in plugins through__internal__registerBuiltinPlugin,
and writes the page (the template with<%= htmlWebpackPlugin.options.title %>,meta,base,inject,scriptLoading,filename) with a
<script>and<link>for each initial chunk. Another built-in plugin is named in a warning. - A JSX spread child (
<List>{...items}</List>) builds in the automatic runtime (children: [...items]). - A decorator on a class field uses the output's names for what it refers to (it kept the source name when the bundler had renamed an
import, as with Lit's@property). - A script may import a file of
public/by its address (import icons from '/icons.svg', which a Vue template with<use href="/icons.svg#a">
becomes): the project folder is tried, thenpublic/, when no such file is on the disk. import.meta.globpatterns may start with an alias (@/views/**/*.vue), from--aliasor the configuration'sresolve.alias
when it maps a name to a path.- A configuration file that imports another file without its extension (
./config/options, usual in a TypeScriptvite.config.ts)
is bundled first, as Vite does, when Node cannot follow the import. - A part of a file that a plugin names by language (
Page.vue?vue&type=script&lang.ts) is read as that language, so the
TypeScript in a Vue<script setup lang="ts">block builds. - A TypeScript function overload signature inside another function is removed from the output (it was left as a
bodilessfunction f(obj), a syntax error). - In a TypeScript file,
export { Draft } from "./x"of a name that module does not export is taken to be a type and left out
of the output, astscand esbuild do, and no longer an error.
v0.1.0-alpha.1
The program is the same as in 0.1.0-alpha.0. This is the first release whose npm packages and crate were published by the
release workflow, with provenance: check them as docs/verifying.md describes.
v0.1.0-alpha.0
First release.
The registries only accept trusted publishing from a package that already exists, so the npm packages and the crate of this
first version were published by hand, without provenance. Their files are the ones attached to this release: compare them
with SHA256SUMS as docs/verifying.md describes. Every later release is published by the release workflow, with provenance.
Added
- A bundler for JavaScript, TypeScript, JSX, JSON and CSS with no dependencies (not even crates):
module graph, linking, tree shaking, code splitting, minifying, source maps, defines, loaders
(text, base64, data URL, binary, file, empty, CSS and local CSS) and?raw,?urland?inline
import suffixes. - Plugins: Rollup and Vite plugins, esbuild plugins, webpack loaders and compiler plugins, and
Parcel plugins, run by a Node 24 or later process. What is covered by tests is listed in the README. - Module federation: containers, remotes, shared packages, the manifest, generated and consumed
types, runtime plugins and development servers, compatible with the containers rspack and
Vite build (tested in Chromium). --watchandserve(a development server with live reload). Stopping--watchcleanly with Ctrl-C is tested on
Linux and macOS only.- Release files: one tarball per platform,
SHA256SUMS, an SBOM that lists zero components, and
Sigstore signatures. The binaries are not signed with an operating-system key; see
docs/verifying.md. - The command is
rkp.rkp --version. - Pages:
rkp bundle index.html --outdir distbuilds the module scripts and linked style sheets a page names, copies the
images and media it names andpublic/, rewrites the page, and runs plugins'transformIndexHtmlon it (ES modules, or
one file with--format iife). --banner,--footer,--drop:console,--drop:debugger,--packages=external,--resolve-extensions,
--preserve-symlinks,--pure,--metafile,--entry-names,--chunk-names,--out-extension,--legal-comments,--inject,--jsx-dev,--tsconfig-raw; an unknown option is an error.- Module federation:
getPublicPath,dtsoutputDir,generateAPITypes,additionalFilesToCompile,abortOnError,timeout,maxRetries,remoteTypeUrlsanddev.disableLiveReload/disableHotTypesReloadare used; what is not carried out is named in a warning. - Module federation:
compilerInstance,extractThirdParty,extractRemoteTypes,afterGenerate,family,remoteTypesFolder,consumeAPITypes,runtimePkgsand the routerbridgeare carried out; onlydts.implementationis named in a warning. --target: object rest is rewritten wherever it is (nested in other patterns, after computed keys, in assignments andcatch); a return on an async generator suspended inyield*ends it; an async arrow with a rewritten body (??,?.) no longer gets its wrapper twice.--targettakes engines with versions (chrome80,safari13.1,node18,firefox78,ios14.5,edge90,opera70), alone or with years in a comma-separated list; only what one of them lacks is rewritten. Class fields, private members and static blocks are rewritten together when an engine lacks any of them.--target: top-level await is rewritten for targets that lack it when the program is one file with nothing exported (the whole program becomes an async function, or a generator run by__asyncbelow es2017).- JS API:
pluginstakes plugin objects (their hooks run in the calling process, across a local socket;emitFile,parse,getModuleInfoand the other context methods that answer at once work, andconfigureServergets middlewares andws.send) and{ module }descriptors. rkp serve --https(with--https-certand--https-key, or a self-signed certificate it makes and keeps): TLS (HTTP/2, or HTTP/1.1 for clients that ask for it) through a Node.js proxy in front of the dev server.rkp serve --hmr: changed modules are replaced in the open page (import.meta.hot.accept,dispose,data,decline,invalidate), with the page reloading only when a change reaches an entry nothing accepts; top-level await and decorators work, and React Fast Refresh keeps the state of components (whenreact-refreshis installed).- Plugins: Vue (
@vitejs/plugin-vue) and Svelte 5 (@sveltejs/vite-plugin-svelte) work, including under--hmr; hooks written as objects with ahandler,configEnvironment, theservecommand, andlang.<ext>queries (?vue&type=style&lang.css) are understood. - A normal bundle no longer breaks when a module declares a top-level name the helpers use (lodash-es declares
Symbol). - Tested in headless Chromium only: the development server,
--hmrand federation have not been tried in Firefox or Safari. - The development server (and the HTTPS proxy) answers on both loopback addresses when the host is
localhost; before, it listened on the first addresslocalhostresolved to, sohttp://127.0.0.1:PORTwas refused on machines where that is::1. - A hook of a plugin object that calls a blocking context method (
emitFile,parse,getModuleInfo, ...) could wait forever on a machine with few cores; the answer is now awaited without that race. - JSX: a space between two elements on one line (
<a/> <b/>) is kept, as Babel and esbuild keep it. --dts-bundle: one merged.d.tsfor each entry instead of one for each source file.--dtsand--dts-dir: declaration files for the entries, written with the project'stypescript(JS APIdts,dtsDir).--target=es2015toes2025:**,?.,??, logical assignment, numeric separators, optionalcatchand trailing commas
and object spread and rest (in declarations, parameters andfor of), class fields, private members and static blocks are
async functions (below es2017),for awaitand async generators (below es2018) are rewritten for targets that lack them; what cannot be rewritten stops the build and is named.import.meta.envwithMODE,DEV,PROD,SSR,BASE_URLand theVITE_variables of.envfiles (--mode,--env-dir,
--env-prefix,--no-env-files).- Dynamic imports with a variable in the path (
import(./locales/${name}.js)), with the rules of Rollup's plugin for them. ./a.wasm?initinstantiates a WebAssembly module (a function, as Vite's).import.meta.glob, and workers (new Worker(new URL(...)),?worker,?sharedworker, with&inlineand&url).- Builds for linux (x64 and arm64, glibc and musl), macOS (arm64 and x64) and Windows (x64). The unit tests that use fake
Unix paths run on Unix only; each release build bundles and runs a program with the binary it made. - A JavaScript API in
@rathkit/pack:build(options),serve(options),run(args), with types. - npm packages:
@rathkit/pack(a launcher) and one package per platform, published with provenance on thenexttag.