Best viewed on desktop Mobile Friendly tutorial coming soon!

Shipping It for Real

Back in the library. It builds, and you’ve watched a real app consume it. One question left: what actually goes in the box?

  1. Run pnpm build, then ask the packer what it would ship:

    Terminal window
    npm pack --dry-run

Read the Tarball Contents list carefully. It shipped src/. It shipped your tsconfigs. And dist/ — the built output, the entire point — isn’t in there at all, because dist is gitignored and npm falls back to your ignore rules when you don’t tell it otherwise. The package contains precisely the wrong half of the project.

  1. Add the allowlist to package.json:

    "files": ["dist", "marko.json", "README.md"],
  2. Run npm pack --dry-run again. Now it’s dist/tags/**, marko.json, package.json. Nothing else — and that list is the box.

That’s npm publish rehearsed. The only step left is the publish itself, which needs an account and a name nobody has taken — and which does exactly what you just watched, to a registry instead of a file.

Two lines you cannot test from in here. Both shipped broken in real published packages, past fully green test suites, and the reason they got through is the same in both cases: nothing inside the repo ever resolves the package the way a stranger does.

sideEffects. Marko templates register their renderers as a module side effect. Say "sideEffects": false — which is correct in most JS packages, and arrives by copying a React one — and a production bundler is licensed to drop a tag’s client module whenever the page never calls a function from your package. A page that only displays your tag is exactly that page. The server sends HTML whose resume payload points at registrations that never ran, and the browser throws effects[(i++)] is not a function and hydrates nothing. Dev mode is fine. Every dev-mode test is fine. The correct value is ["**/*.marko"], which is already in this file.

The "./dist/tags/*" export. When a consumer’s app builds, Marko’s compiler rewrites each discovered tag into a bare specifier through your package — marko-fancy/dist/tags/fancy-badge/index.marko — and their bundler resolves it through your exports map. Without that one line, every real consumer build fails with Missing "./dist/tags/..." specifier, while dev servers and type-checks stay perfectly green.

That’s the chapter, and the part. You can type a Marko app, test it, look at it, lint it, build it into a package, and hand that package to a stranger who types one tag name and gets your work — with the types.

Powered by WebContainers Built with TutorialKit Built with ❤️ by defunkt-dev
Files
Preparing Environment
  • Installing dependencies
  • Building the library