UNPKG

universal-emoji-parser

Version:

This tool allow parse unicode and emoji codes to html images using emojilib && Twemoji CDN

378 lines (268 loc) 15.9 kB
# Build & Deploy How Universal Emoji Parser is built, versioned, and published. The release path is **fully automated** via GitHub Actions — humans rarely run any of the commands in this document by hand. ## Inputs you need before any release - **GitHub remote** with push + tag access for the release bot (`secrets.AUTOMATION_GITHUB_TOKEN`) - **npm publish access** for the `universal-emoji-parser` package (`secrets.NPM_TOKEN`) - **DailyBot notification credentials** (`secrets.DAILYBOT_API_KEY`, `vars.DAILYBOT_DEPLOYMENT_NOTIFICATION_CHANNEL`) — non-blocking; messages just fail silently if absent The fork checklist for these is in [Fork Customization](FORK_CUSTOMIZATION.md). --- ## The build artifact `npm run build` produces a single bundle in `dist/`: ``` dist/ ├── index.js ← Webpack production bundle (~600 KB minified, catalog inlined) ├── index.js.map ← Source map (production: minimal; dev: full) ├── index.d.ts ← TypeScript declarations (emitted by tsc --build separately) └── lib/ └── type.d.ts ← Re-exported interface types ``` `package.json` points consumers at: ```json { "main": "dist/index.js", "types": "dist/index.d.ts" } ``` `dist/` is **gitignored**. CI rebuilds it before publishing; nobody commits it. ### Manual build ```bash npm run build # Webpack production (minified, single file, CleanWebpackPlugin) npm run build:tsc # tsc --build (emits .d.ts) ``` **Both** must run before `npm publish` because: - Webpack produces `dist/index.js` (executable) - tsc produces `dist/index.d.ts` (types) The CI workflow runs `npm run build` (which is Webpack-only) — that's enough because Webpack with `ts-loader` also emits declarations when configured. Currently it doesn't, so tsc is the source of truth for `.d.ts`. **If you find missing types in the published package, add `npm run build:tsc` to the release workflow before `npm publish`.** ### Inspecting the bundle ```bash ls -lh dist/index.js # Bundle size node -e "console.log(Object.keys(require('./dist/index.js')))" # Exported keys node -e "console.log(require('./dist/index.js').parse('hello :smile:'))" # Smoke run ``` The exported keys should be: `default`, `DEFAULT_EMOJI_CDN`, `emojiLibJsonData`, plus the `parse`, `parseToHtml`, etc. methods on the default. The CommonJS reattachment in `src/index.ts` ensures `require('./dist/index.js')` returns `uEmojiParser` directly (not `{ default: uEmojiParser }`). --- ## Versioning The package follows **Semantic Versioning** (loosely): - **Patch** (e.g., `2.0.79` → `2.0.80`) — bug fixes, catalog regenerations, dep bumps without API change. CI auto-bumps on every PR merge - **Minor** (e.g., `2.0.x` → `2.1.0`) — new methods, new options, new catalog fields. **Manually bump** before merging - **Major** (e.g., `2.x` → `3.0`) — HTML output template change, default option flip, removed/renamed method, dual-export break, dropped Node version CI's `npm version patch -m "[🤖 DailyBot] New release to v%s launched 🚀"` is the right default. ### How to ship a non-patch release The release workflow auto-runs `npm version patch`, which fails if the working tree is dirty or if the new version already exists. To ship a minor or major: 1. **In the same PR**, edit `package.json` `"version"` manually to the next minor or major (e.g., `2.0.79` → `2.1.0` or `3.0.0`) 2. Note in the PR description that this is a non-patch release 3. The workflow's `npm version patch` will then bump from `2.1.0` → `2.1.1` (or `3.0.0` → `3.0.1`) — which is fine 4. **Or**: temporarily disable the auto-bump in the workflow for that release, manually run `npm version minor`/`major` locally, push the tag, and re-enable the workflow Right now the workflow has no toggle — modifying it is the way. File an issue if this happens often; we'll add a `[skip auto-bump]` PR-title convention. --- ## CI release pipeline `.github/workflows/release_and_publish.yml` runs on: ```yaml on: pull_request: branches: [main] types: [closed] ``` …and gates every step on `if: github.event.pull_request.merged == true` (so closing a PR without merging doesn't trigger a release). ### Job graph ``` check_pr_size_label │ ▼ notify_on_channel_start │ ▼ deploy_setup (npm install) │ ▼ deploy_validate_linters_and_code_format (eslint:check + prettier:check) │ ▼ deploy_tests (npm test) │ ▼ build (npm run build) │ ▼ release_and_publish (version bump + tag + GH release + npm publish) │ ┌──────────┴──────────┐ ▼ ▼ cleanup_caches notify_on_channel_end ``` Every job runs on `ubuntu-latest` with Node **24** (latest `.x` available to `actions/setup-node`) and aggressive caching of `~/.npm`, `node_modules`, and `dist/`. ### Job-by-job #### 1. `check_pr_size_label` Reads the PR's labels for one of `Size - XS / S / M / L / XL / XXL` (set by `pull_request_check.yml`) and emits an emoji indicator (`🟢`/`🟡`/`🟠`/`🔴`) used in the channel notification. Pure metadata — doesn't gate the release. #### 2. `notify_on_channel_start` Posts a "deployment started" message to the DailyBot channel via `https://api.dailybot.com/v1/send-message/`. Includes PR number, title, body, size label, and workflow URL. #### 3. `deploy_setup` `actions/checkout@v6` + `actions/setup-node@v6` (Node 24) + `actions/cache@v5` for `~/.npm` and `node_modules`. If cache miss, runs `npm install`. #### 4. `deploy_validate_linters_and_code_format` ```yaml - run: npm run eslint:check - run: npm run prettier:check ``` Hard gate. Fails the whole pipeline if either lint check fails. #### 5. `deploy_tests` `npm run test` — Mocha + Chai over `test/**/*.ts` via **tsx**. Hard gate. #### 6. `build` ```yaml - run: | npm run build if [ ! -d "dist" ]; then echo "⚠️ Error: dist folder does not exist." exit 1 fi ``` Webpack production build. Caches `dist/` so the next job can publish without rebuilding. > **Gotcha:** the workflow doesn't run `npm run build:tsc` — only Webpack. If a consumer reports missing types in a published version, that's why. Fix is to add `npm run build:tsc` to the build job (a one-line change). #### 7. `release_and_publish` ```yaml - uses: actions/checkout@v6 with: fetch-depth: '30' # need history for release notes token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }} - uses: actions/setup-node@v6 with: node-version: '24' registry-url: https://registry.npmjs.org/ - run: | git config user.name "🤖 DailyBot" git config user.email "ops@dailybot.com" - run: | bash .github/scripts/get_github_release_log.sh - run: | npm run release git push --follow-tags origin main - run: | GITHUB_RELEASE_TAG=$(git describe --tags $(git rev-list --tags --max-count=1)) echo "::set-env name=GITHUB_RELEASE_TAG::$GITHUB_RELEASE_TAG" - uses: ncipollo/release-action@v1 with: name: Release ${{ env.GITHUB_RELEASE_TAG }} tag: ${{ env.GITHUB_RELEASE_TAG }} bodyFile: git_logs_output.txt token: ${{ secrets.AUTOMATION_GITHUB_TOKEN }} - run: | npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | git push origin --delete "${{ github.event.pull_request.head.ref }}" ``` Steps in order: 1. **Checkout** with token + 30-commit history (for the release notes script) 2. **Identity** — git as `🤖 DailyBot <ops@dailybot.com>` 3. **Release notes** — `get_github_release_log.sh` walks `git log` from HEAD until it hits the previous `[🤖 DailyBot] New release to v...` commit, formats each as `🚩 <message>`, writes `git_logs_output.txt` 4. **Bump version** — `npm version patch -m "[🤖 DailyBot] New release to v%s launched 🚀"` updates `package.json`, creates a tag, commits 5. **Push** — `git push --follow-tags origin main` (sends the version commit + the tag) 6. **GitHub Release** — `ncipollo/release-action@v1` creates a Release with notes from step 3 7. **npm publish** — uses `secrets.NPM_TOKEN` via `NODE_AUTH_TOKEN`. The package goes live on npm 8. **Delete source branch** — tidies up the merged feature branch #### 8. `cleanup_caches` Triggers `cleanup_caches.yml` via `repository_dispatch` to GC stale GHA caches. #### 9. `notify_on_channel_end` Posts the final status (success/failure per job) to the DailyBot channel. Always runs (`if: always()`) so failures get reported even when an earlier job blew up. --- ## What gets published to npm `.npmignore` excludes everything except what consumers need: | Included in tarball | Excluded | | ------------------- | ----------------------------------------------------------------------------------------------------- | | `dist/` | `src/` | | `package.json` | `test/` | | `README.md` | `webpack.config.js`, `tsconfig.json`, `.babelrc`, `eslint.config.mjs`, `.prettierrc`, `.editorconfig` | | `LICENSE` | `.github/`, `docker/`, `.vscode/`, `.devcontainer/`, `.agents/`, `.claude/`, `docs/` | | | `package-lock.json`, `git_logs*.txt`, `packages_upgrades*.txt`, `emoji-lib-output.json` | Verify what would publish without actually publishing: ```bash npm pack --dry-run # Lists files; does not publish npm pack # Creates universal-emoji-parser-X.Y.Z.tgz locally tar tzf universal-emoji-parser-*.tgz | sort ``` If you ever see `src/`, `test/`, or config files in the tarball, fix `.npmignore`. --- ## Manual release (CI down or emergency) ```bash # 0. Make sure main is clean and up to date git checkout main git pull git status # must be clean # 1. Lint, test, build npm install npm run eslint:check npm run prettier:check npm test npm run build npm run build:tsc # 2. Bump version (this commits + tags) npm version patch -m "[🤖 DailyBot] New release to v%s launched 🚀" # 3. Push commit + tag git push --follow-tags origin main # 4. Generate release notes bash .github/scripts/get_github_release_log.sh cat git_logs_output.txt # review # 5. Publish to npm (must have NPM_TOKEN configured or be logged in) npm publish # 6. Create the GitHub release manually via gh CLI TAG=$(git describe --tags --abbrev=0) gh release create "$TAG" --notes-file git_logs_output.txt --title "Release $TAG" ``` This bypasses the DailyBot notifications and the cache cleanup — if you're doing a manual release, you've already accepted that those won't fire. Walk through [`/release-npm`](../.agents/commands/release-npm.md) for the structured version. --- ## Pull request workflows (gating, not releasing) ### `code_check.yml` — runs on every PR Three jobs: `setup` → `validate_linters_and_code_format` → `tests`. Gates merging. ### `pull_request_check.yml` — runs on PR open/edit Computes the PR size label from `git diff --shortstat` (lines added + removed) and applies one of `Size - XS / S / M / L / XL / XXL`. Posts a warning comment for L+. Also enforces minimum title length (10 chars) and body length (30 chars). These exist for review hygiene; they don't directly affect the release. --- ## Dependency upgrade pipeline ### `check_packages_versions.yml` — runs every Tuesday 15:00 UTC 1. Checks out a branch named `feature__packages_versions_update` (creates if missing) 2. Runs `npm run ncu:upgrade` (respects `.ncurc.json` — chai 4 / eslint 8 stay pinned) 3. If anything upgraded, commits `Upgrading packages versions`, pushes the branch 4. Opens a PR titled `🤖 Upgrading packages versions` with the upgrade list as body 5. Notifies DailyBot ### `check_and_merge_packages_upgrades_pr.yml` Auto-merges that PR when CI is green. The merged PR then triggers `release_and_publish.yml`, which patch-bumps and publishes — the dep upgrade ships within hours. This is fully automated; humans only review when something breaks. --- ## Forking the release infrastructure If you're forking this repo (see [Fork Customization](FORK_CUSTOMIZATION.md)): 1. **Create a `secrets.NPM_TOKEN`** in your fork's GitHub repo settings (npm → Profile → Access Tokens → Generate New Token, select "Automation") 2. **Create a `secrets.AUTOMATION_GITHUB_TOKEN`** — a fine-grained PAT or GitHub App token with `contents: write`, `pull-requests: write`, `metadata: read` on the fork 3. **Either set or unset DailyBot vars/secrets** — without them the notification steps fail (silently for `success` runs, visibly for `failure` runs). Easiest path: gut the `notify_on_channel_*` jobs from your fork's workflow 4. **Update the package name** in `package.json` to your scoped package (`@myorg/emoji-parser`) so npm publish doesn't conflict --- ## Common build failures ### `npm publish` 403 Forbidden - `NPM_TOKEN` expired or wrong scope (needs `automation` or `publish`) - Package name conflict — the name `universal-emoji-parser` is taken by this repo; if you fork and rename, register the new name first - Org permission missing — for scoped packages, the publishing user must have `developer` or above in the org ### Webpack build is empty / missing methods - `ts-loader` failed silently — check `dist/index.js` size; if it's tiny (<10 KB), the catalog wasn't bundled. Likely a `tsconfig.json` change broke `resolveJsonModule: true` ### `git push --follow-tags` rejected - Branch protection on `main` requires PRs — but the release workflow pushes directly. Verify the bot's token has the "bypass branch protection" toggle enabled, or weaken protection for that token - Tag already exists — manual push happened previously; delete the local tag and let CI retry ### npm version says "git working tree is not clean" - A previous step modified files (e.g., a test wrote to `dist/`). The workflow caches `dist/` between jobs; if it's dirty, the version bump aborts - Manual fix: `git checkout -- .` before `npm version`, or stage cleanly --- ## Deployment checklist - [ ] `npm run eslint:check` succeeds - [ ] `npm run prettier:check` succeeds - [ ] `npm test` passes - [ ] `npm run build` produces `dist/index.js` - [ ] `npm run build:tsc` produces `dist/index.d.ts` (manual releases only — CI doesn't) - [ ] `npm pack --dry-run` shows only the expected files - [ ] No `console.log` in `src/` - [ ] `package.json` `version` reflects the intent (patch/minor/major) - [ ] Release notes draft makes sense (`bash .github/scripts/get_github_release_log.sh && cat git_logs_output.txt`) - [ ] `NPM_TOKEN` and `AUTOMATION_GITHUB_TOKEN` are valid (CI will fail fast if not)