Created
August 19, 2025 23:19
-
-
Save ammuench/9363b87715fee9b28062dba8d6a92e88 to your computer and use it in GitHub Desktop.
Annotated workflow for publishing deno packages to NPM with Github CI and Deno-to-node
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## | |
| ## Quick annotated example file to build a Github CI workflow to publish your Deno package to | |
| ## npm using Deno-To-Node (https://github.com/denoland/dnt) whenever you create and publish a | |
| ## new versioned system tag! | |
| ## | |
| ## Could also be easily used to build and deploy standard node packages to NPM with just a little bit of tweaking | |
| ## | |
| name: Publish to NPM | |
| on: | |
| push: | |
| # Runs on creation of tags created of type v.X.Y.Z (eg `tag -a v2.3.21`) | |
| tags: ["v*"] | |
| workflow_dispatch: | |
| # Allows for user to manually trigger a tag publish event | |
| inputs: | |
| tag: | |
| description: "Tag to publish (e.g., v1.0.0)" | |
| required: true | |
| type: string | |
| jobs: | |
| validate: | |
| name: Pre-publish Validation | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Deno | |
| uses: denoland/setup-deno@v1 | |
| with: | |
| deno-version: v2.x | |
| # Gets version from workflow dispatch or tag name | |
| - name: Extract version from tag | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.tag }}" | |
| else | |
| VERSION="${GITHUB_REF#refs/tags/}" | |
| fi | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "Publishing version: ${VERSION}" | |
| # Ensure that tag passed matches what you have in the deno.json manifest | |
| # (this will pass to the package.json file as part of the DNT build step) | |
| # | |
| # You could remove this if you want have more control to deploy manually | |
| # and potentially add in something that adds the tag to your deno.json in this flow | |
| - name: Verify version in deno.json matches tag | |
| run: | | |
| DENO_VERSION=$(jq -r '.version' deno.json) | |
| TAG_VERSION="${{ steps.version.outputs.version }}" | |
| TAG_VERSION_CLEAN="${TAG_VERSION#v}" | |
| if [ "$DENO_VERSION" != "$TAG_VERSION_CLEAN" ]; then | |
| echo "Error: Version mismatch!" | |
| echo "deno.json version: $DENO_VERSION" | |
| echo "Tag version: $TAG_VERSION_CLEAN" | |
| exit 1 | |
| fi | |
| # Re-run basic quality checks before we start publishing. Add any other required commands here | |
| - name: Run quality checks | |
| run: | | |
| deno fmt --check | |
| deno lint | |
| deno test | |
| build-and-publish: | |
| name: Build and Publish to NPM | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| environment: publishing | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Deno | |
| uses: denoland/setup-deno@v1 | |
| with: | |
| deno-version: v2.x | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v3 | |
| with: | |
| node-version: "22" | |
| registry-url: "https://registry.npmjs.org" | |
| # Run DNT build script, add any other prerequesite steps here if needed | |
| - name: Build NPM package with dnt | |
| run: deno run -A scripts/build_npm.ts | |
| # Ensure the built package.json inhereted the right version from the deno.json file | |
| - name: Verify NPM package version matches tag | |
| run: | | |
| NPM_VERSION=$(jq -r '.version' npm/package.json) | |
| TAG_VERSION="${{ needs.validate.outputs.version }}" | |
| TAG_VERSION_CLEAN="${TAG_VERSION#v}" | |
| if [ "$NPM_VERSION" != "$TAG_VERSION_CLEAN" ]; then | |
| echo "Error: NPM package version mismatch!" | |
| echo "npm/package.json version: $NPM_VERSION" | |
| echo "Tag version: $TAG_VERSION_CLEAN" | |
| exit 1 | |
| fi | |
| # Ensure all your files are properly created from the DNT build script | |
| # Add/remove things here as needed | |
| - name: Verify package structure | |
| run: | | |
| test -f npm/package.json | |
| test -d npm/esm | |
| test -d npm/script | |
| test -f npm/LICENSE | |
| test -f npm/README.md | |
| - name: Test NPM package imports | |
| working-directory: npm | |
| run: | | |
| # Test CommonJS import, you can remove this if you don't plan to export CJS | |
| node -e "const contrastrast = require('./script/mod.js'); console.log('CommonJS import successful:', typeof contrastrast);" | |
| # Test ESM import | |
| node -e "import('./esm/mod.js').then(m => console.log('ESM import successful:', typeof m.default || typeof m));" | |
| - name: Publish to NPM | |
| working-directory: npm | |
| env: | |
| # Tokens can be generated from https://www.npmjs.com/settings/YOUR_USERNAME/tokens | |
| # Make sure to add it as a secret to your GH Action in your repo settings | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| run: | | |
| if [[ "${{ needs.validate.outputs.version }}" == *"-"* ]]; then | |
| echo "Publishing non-stable release with beta tag" | |
| npm publish --tag beta | |
| else | |
| echo "Publishing stable release" | |
| npm publish | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment