How to Publish a Fully Production‑Ready npm Package from Scratch
This step‑by‑step guide shows how to initialize a Git repository, configure TypeScript, Prettier, Vitest, CI with GitHub Actions, set up package metadata, use Changesets for versioning, and finally build and publish a production‑ready npm package.
In this tutorial we start from an empty directory and walk through publishing a fully production‑ready npm package, covering version control, TypeScript, formatting, testing, CI, and release automation.
Use git init to create a new repository.
Create a .gitignore containing node_modules.
Make the initial commit with git add . and git commit -m "Initial commit".
Create a new GitHub repository (e.g., tt-package-demo) and push the code.
1.5 Create core files
Generate package.json with fields such as name, version, description, keywords, homepage, bugs, author, repository, files, and type. Add a license field (MIT), a LICENSE file, and a README.md describing the package.
2. Install TypeScript
npm install --save-dev typescriptAdd a .prettierrc file with preferred formatting options and a format script in package.json that runs prettier --write .. Also add a check-format script that runs prettier --check ..
3. Configure the project
Create tsconfig.json with strict compiler options, enabling ES module interop, skipping lib checks, targeting es2022, allowing JS, resolving JSON modules, and generating declarations.
Optionally add a lib entry when the code does not need DOM APIs.
4. Add source files
Create src/utils.ts exporting a simple add function, and src/index.ts re‑exporting it.
5. Build scripts
Add a build script that runs tsc (later replaced by tsup), and a ci script that runs
npm run build && npm run check-format && npm run check-exports.
6. Export validation
Install @arethetypeswrong/cli as a dev dependency and add a check-exports script ( attw --pack .) to verify that the package exports resolve correctly for Node and bundlers.
Set the main field to dist/index.js and add an exports map pointing import to dist/index.js and default to dist/index.cjs. Include ./package.json in the exports map.
7. Switch to tsup
Install tsup and create tsup.config.ts defining entry points, output formats ( cjs and esm), declaration generation, output directory, and clean build.
Update the build script to run tsup instead of tsc.
8. Linting
Add a lint script that runs tsc as a type‑checking linter, and include it in the ci script.
9. Testing with Vitest
npm install --save-dev vitestCreate src/utils.test.ts testing the add function, add a test script ( vitest run), a dev script ( vitest) for watch mode, and extend the ci script to run tests.
10. GitHub Actions CI workflow
name: CI
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm install
- name: Run CI
run: npm run ci11. Changesets for versioning
Install @changesets/cli, run npx changeset init, set access to public and commit to true in .changeset/config.json. Add a local-release script ( changeset version && changeset publish) and a prepublishOnly script ( npm run ci).
Create a changeset with npx changeset, commit the changes, and run npm run local-release to publish the package to npm.
Summary
The guide sets up a TypeScript project with Prettier, export validation, tsup bundling, Vitest testing, GitHub Actions CI, and Changesets for automated versioning and publishing a production‑ready npm package.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
