docs/cross-domain-browser-matrix
12
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
23be25d84a |
Fix seven widget defects, including the cookies the separate-domain setup needs (#2197)
* Drop the frontend workspace root and re-resolve the lockfile
`frontend/` carried a `package.json`, a `pnpm-workspace.yaml` and the lockfile
for a workspace of exactly one package. Two manifests meant two places to
declare a version, and the app pin was the one that did not win: `preact` and
`@babel/core` were each written twice, and a bump to the app manifest alone
would have been a silent no-op, since `pnpm.overrides` decides and it lived at
the root.
Everything pnpm reads now lives in `frontend/apps/remark42`: dependencies,
`packageManager`, `engines` and the overrides. `frontend/` keeps `.nvmrc`,
`.husky` and `CLAUDE.md`, none of which pnpm reads. The directory nesting
stays: every path in the repository points at `frontend/apps/remark42`,
including the published contributing docs, so moving the package up would have
rewritten 14 files to no benefit.
Moving the manifest kept the old resolutions verbatim, which left optional peer
subtrees the tree no longer reaches: `ts-node` under jest, `@swc/core` under
webpack, `vitest` under `@testing-library/jest-dom`, `tslib` under
`webpack-dev-server`. None is referenced by any config or source file here.
Re-resolving drops 137 packages and moves 59 to versions already permitted by
the ranges in the manifest, 1446 to 1308, with no direct dependency changing
version: the five that look changed differ only in their peer suffix. Every
file `pnpm build` produces is identical in size before and after.
The frontend-deps stage of the Dockerfile sets `CI=true` so the `prepare`
script skips husky, which has no git repository to install hooks into there.
* Stop markdown-only changes triggering heavy workflows, and check the documented versions
`ci-backend.yml`, `ci-build.yml` and `ci-frontend.yml` all end their path
filters with `!**.md`. The e2e workflow did not, so a change to any markdown
file under `frontend/` or `backend/` matched its `frontend/**` and `backend/**`
entries and started a docker build and the whole browser suite. The release
filter had the same hole and two of its own: it names `README.md` and `LICENSE`
on purpose, since `.goreleaser.yml` packages both, so it now excludes markdown
under `backend/` and `frontend/` only. `CLAUDE.md` and the installation page
were listed as well, and neither is packaged.
`ci-site.yml` goes on matching markdown, which is right, since the site is
built from it. It excludes `CLAUDE.md`, so a future `site/CLAUDE.md` cannot
start a site build, and `site/README.md`, which documents how to build the site
rather than being part of it.
The installation page tells a reader that a source build needs Go 1.25, Node
24+ and PNPM 10. Nothing kept those in step with `backend/go.mod`,
`engines.node`, `packageManager` and `.nvmrc`, and the drift is silent: a wrong
version in the docs builds and tests exactly as well as a right one. `.nvmrc`
is the pin with form here, having sat at 16 through the whole node 20 migration
because nothing red ever pointed at it. The check compares each stated version
against its source and holds `.nvmrc` to `engines.node`, and it fails when the
page states no version at all, so removing the claims cannot turn it into a
check that passes by comparing nothing.
Its own workflow rather than a step in an existing one, since the inputs span
the backend module, the frontend manifest and the site.
* Fix the cookie fallback page, asset path, message senders, auth teardown and cookies
Two defects with the same origin:
|
||
|
|
0b651dddd4 |
Make backend tests wait on conditions instead of durations (#2190)
* Make backend tests wait on conditions instead of durations The backend workflow has a long tail of runs that fail once and pass on a rerun. Every one of them comes down to a test assuming an operation finishes within some duration rather than waiting for the state it needs. Three were reproducible and each was reproduced against the old code before being changed: TestServerAuthHooks minted a token that lived one second and never tested expiry, so a slow runner turned the first POST into a 401; TestServerApp_AnonMode saw "connection refused" because waitForHTTPServerStart returned silently after three seconds and left a later assertion to fail with something unrelated; TestFsStore_Cleanup slept 200ms against a 300ms ttl that Cleanup widens to 400ms with its commit grace, so roughly 100ms of stall collected an image meant to survive. Fixed sleeps before asserting on asynchronous work are replaced with polls on the condition itself, using require.Eventually and require.EventuallyWithT, and require.Never where the assertion is that something did not happen. Polling closures assert on the CollectT they are handed rather than on t, since testify runs them on another goroutine, and polls that issue HTTP requests stay under the rate limit on the routes they poll through. Where a test needs time to have passed, the clock input is pinned instead: staging ages are stamped with os.Chtimes on both sides of the cleanup boundary right before each call, which also makes the 100ms commit grace an exact case rather than something no assertion reaches, and the RSS tests set store.Comment.Timestamp explicitly rather than racing the wall clock into the first 100ms of a second so pubDate matches. chooseUnusedPort takes a port from the kernel's ephemeral range. Picking at random out of a fixed 10000-port window let two package binaries, which go test ./... runs concurrently, land on the same number between the probe closing and the server binding. The start helpers fail naming the port they waited on, and the SSL tests wait on the redirect port as well as the TLS one. Arbitrary budgets that nothing tests are gone: ten HTTP clients with a one-second timeout against bolt-backed import and export, the "should take about 100msec" assertions, and a one-second bound on noticing an already cancelled context. Shutdown stays bounded at ten seconds so a hang is still caught. Two assertions get stronger. TestServerAuthHooks accepted 403 or 401 from a blocked user, an alternative that existed only because the short token could expire mid-test; it is deterministically 403 now. TestAdmin_BlockedList asserted two users blocked while one carried the same 150ms ttl the next step waits to lapse, so the halves raced each other. goleak stops reporting the regexp2 clock goroutine, which chroma pulls in for syntax highlighting and which lives for up to a second after the last match with a timeout; it ends on its own but a binary finishing inside that window was reported as leaking, and this suite now finishes sooner. The ignore for net/http.(*Server).Shutdown goes the other way: it no longer matches anything, with both packages run fifteen times each under CPU oversubscription to confirm. Two gaps the change would otherwise have opened are covered directly rather than left to the side effects that used to cover them. The one-second token was the only thing exercising the authenticator's ClaimsUpd hook on refresh, so TestServerApp_ClaimsUpd now calls the hook itself and checks admin, blocked, email and restricted-name impersonation, including the two pass-through cases. Lifting the open-route limit removed the last incidental exercise of the rate limiter, so TestRateLimiter drives a burst past the allowance and checks the refusals and that the limit is per client. Both run without a wall clock, and both were confirmed to fail when the behaviour they cover is removed. Production code is untouched. The two sleeps outside test code, the 429 backoff in cmd/cleanup.go and the submit poll in store/image/image.go, are left alone: no CI failure implicates them. Test sleeps drop from 67 to 21, all of them either inside a testing/synctest bubble or a poll interval. The suite runs in about 22 seconds instead of 46, mostly because TestPublic_FindCommentsCtrl_ConsistentCount no longer paces a hundred subtests with an 80ms sleep each to stay under the open route limit. The 300s per-package budget now matches across both workflows, the race_test target and the documented command, and CLAUDE.md records the convention. with '#' will be ignored, and an empty message aborts the commit. # # Date: Sat Aug 22 01:12:31 2026 +0100 # # interactive rebase in progress; onto |
||
|
|
a5b2fe3cfc |
Consolidate the frontend toolchain onto babel, and ship one bundle (#2178)
Four upgrades that were finished but never merged, the compiler collapse
they enable, and the dependency sweep that follows. Direct
devDependencies go from 78 to 60 and dependencies from 10 to 9.
Three were doing the same job: `ts-loader` stripped types in webpack,
`babel-loader` did everything else, and `@swc/jest` repeated both for the
tests with its own copy of the JSX settings. Babel is the one that
survives, because the `data-testid` stripper has no equivalent elsewhere.
`ts-loader` ran `transpileOnly: true`, so it only stripped types, which
`@babel/preset-typescript` does; `fork-ts-checker-webpack-plugin` was
already what type-checks. Jest runs `babel-jest` against the same
`.babelrc.js` the bundle uses, passed as `configFile` because a
file-relative babel config does not reach the `node_modules` packages in
`transformIgnorePatterns`, and `jest.config.mjs` is plain ESM because a
`.ts` config is compiled against `tsconfig.json`, whose
`verbatimModuleSyntax` rejects ESM syntax in a file the package has not
declared as a module.
That removes `ts-loader`, `@swc/jest` and `@swc/core`. The last was
pinned to 1.2.205 from 2022 with no way forward, because newer builds
emit non-configurable exports and break `jest.spyOn` across 13 suites.
Babel compiles a file at a time with no type information, so it cannot
tell a type-only import from a real one and keeps the module. One line,
`import { boundActions } from './connected-comment'`, pulled the whole
redux store into `last-comments.mjs` and doubled it. `verbatimModuleSyntax`
and `@typescript-eslint/consistent-type-imports` mark them properly; the
statement has to be a separate `import type`, since verbatim semantics
keep an inline `import { type X }` and load the module anyway.
The legacy and modern compilations produced the same bytes. Both read the
same browserslist query, `defaults, not IE 11, not samsung 12` resolves to
chrome 109 and up, and nothing in the source needs transforming for that
set, so 28 of the 29 output pairs were byte-identical.
That made the module/nomodule switch worse than redundant: it served the
`.js` file to browsers with no ES module support, and those files carried
`??`, `?.` and class fields, so the fallback handed its own audience a
syntax error. There is now one bundle, always loaded as a module, in the
five templates and in the seven `site/` documents integrators copy from.
A production build emits 29 files rather than 58, in about 3 seconds
rather than 17. Two of those documents did not work at all beforehand:
the SPA snippet could not parse, and the subdomain example had an
unterminated string.
`@babel/core` 8 declares `^22.18 || >=24.11` and `size-limit` 13 declares
`^22.18 || ^24 || >=26`, so 20 was below the floor of two things installed
here; pnpm only warns, which is why every build passed. All seven places
the frontend pins it move together. `site/` is untouched: it builds with
yarn and eleventy and installs neither.
`eslint --print-config` before and after gives 173 active rules on an
application file against 172, and 172 on a spec file and a plain JS file
against 171. What is gone is three `flowtype` rules with no Flow here,
`no-new-object` and `no-new-symbol` whose upstream replacements are on,
`react/forbid-foreign-prop-types` with no propTypes anywhere, and, on TS
only, `no-useless-constructor`, whose typescript-eslint version is on at
error. `@babel/core` is pinned to 8 across the workspace because
`@jest/transform` and `istanbul-lib-instrument` depend on 7 outright; a
second scoped override holds `eslint-config-preact` on 7, since its
`@babel/eslint-parser` loads babel 7 syntax plugins.
`fast-async` rewrote every async function into nodent promise chains,
calls babel's `transform` synchronously, which babel 8 removed, and every
browser in the target list runs async natively. `prefresh` blew its stack
on `createContext` under babel 8 with no newer release to move to, which
compiled `intl.tsx` and `store/context.tsx` into throwing stubs, so
`pnpm dev:app` could not run the widget at all. `core-js` is not injected
now that `useBuiltIns` is gone, `postcss-custom-properties` was reached
directly although nothing declared it and resolved only through pnpm's
private hoist directory, and `cssnano` ran in both postcss chains although
`CssMinimizerPlugin` already uses it.
`pnpm lint`, `pnpm test` and `pnpm build` now work from `frontend/` as
`CLAUDE.md` and the contributing guide have always said they do; the
workspace root defined none of them.
|
||
|
|
4c9ef37cf1 |
Move the site from eleventy to hugo (#2179)
* Move the site from eleventy to hugo The site is built by a single static binary. No node, no package manager, no lockfile, and the toolchain it needed is gone: eleventy, tailwind, postcss, markdown-it and its three plugins, date-fns, prism, npm-run-all, cross-env and html-minifier-terser. Hugo covers most of that itself. Chroma replaces prism, goldmark replaces markdown-it, `--minify` replaces html-minifier-terser, and fingerprinted asset URLs replace the cache-busting `version` shortcode that stamped `Date.now()` into every stylesheet link. `assets/styles.css` is hand-written, since tailwind was the only reason left to keep a package manager. The palette and the light and dark values are custom properties at the top of the file; the minified stylesheet is 15 kB against tailwind's 46 kB, and the whole build 1.0 MB against 1.2 MB. It was matched to the old one by comparing computed styles rather than by eye, which is how the heading weights and line heights, the list marker colour, and the home page heading and sign-off were caught: the last of those had been carried by tailwind utilities written into the markup. The `::: note` container becomes a `note` shortcode taking the emoji to show. Its closer needs a blank line after it, because a shortcode is not a block rule the way `markdown-it-container` was, and without one goldmark keeps the callout inside the open paragraph. The `overflow-x` wrapper around tables and the heading anchors are goldmark render hooks. Syntax guessing is off. Chroma detected a systemd unit file as gdscript and a chat transcript as mysql, and colouring a snippet as the wrong language is worse than not colouring it. The two chroma themes are scoped to opposite sides of the theme switch rather than layered, because they do not declare the same properties on the same tokens: github gives Error a background github-dark never overrides, and styles Punctuation where github-dark leaves it alone. Layered, either leaves a light value applying on a dark page. `[frontmatter] lastmod` resolves through git, then front matter, then file modification time. Without that chain `.Lastmod` falls back to `.Date`, which is zero when a page carries no date, and every page reads `Jan 01, 0001`. `enableGitInfo` is off because the image build context is `site/` alone, where hugo fails hard rather than degrading; `HUGO_ENABLEGITINFO=true` gives real per-page commit dates locally. Three fixes fall out of the move rather than being sought: - `/docs/` redirected nowhere. The stub was a markdown file whose permalink was a template expression while `markdownTemplateEngine` was false, so it never rendered and the URL 404'd. It is an alias now - `/docs/contributing/` pointed at `/docs/contributing/development/`, which has never existed. It points at the backend page - the 404 page was built to `/404/` and nothing served it. Hugo writes it to `/404.html` and reproxy is told to use it The mobile documentation menu is a checkbox and label. `visibility: hidden` on the checkbox, which is what the old `invisible` utility set, takes it out of the tab order, and a label is not focusable on its own, so the menu could not be opened from the keyboard at all. The checkbox is clipped rather than hidden, and its label shows a focus ring. Content is unchanged. Every code block on every page is byte-identical to the eleventy output; the only prose difference is that two example values, `mysite.com` and a quoted `https://demo.remark42.com`, are no longer turned into links, goldmark's linkify being narrower than markdown-it's. `backend/README.md` and `frontend/apps/remark42/README.md` are symlinks into the docs tree and follow it to `site/content/`, as does the path `release.yml` watches. `frontend/CLAUDE.md` described the site as a node and yarn project in four places. * Keep the heading anchors markdown-it generated Goldmark strips punctuation markdown-it kept, so 22 headings holding a dot, slash, apostrophe, question mark, bracket or em dash would take a new id and any link into one from outside the repository would stop resolving. Those headings carry their previous id as well, as an empty target emitted ahead of the heading by the render hook, from a map of content path to old anchor in `data/anchor_aliases.json`. The map was built by matching heading text between the two builds rather than by position, so it survives a heading being added or moved. The hook rather than markdown, because goldmark's `{#id}` attribute syntax cannot express these: it accepts dots, apostrophes and em dashes but treats a slash, a question mark, a bracket or a percent sign as heading text, which is 11 of the 22. The ids are stored percent-decoded, since a browser decodes a fragment before matching, so `#children%E2%80%99s-privacy` finds `children’s-privacy`. Verified by navigating to the awkward ones against the built image and measuring where the page settles: each lands 112px down, which is the header offset the target carries. Three pages carried no title, so the docs template rendered an empty `<h1>` above the heading their markdown already had. They take their titles from that heading text, so neither the wording nor its anchor changes, and the template's `<h1>` carries an id. One in-page link pointed at an anchor goldmark no longer generates. The heading render hook emits no permalink anchor. The one it replaced was an empty `<a href>` with `pointer-events: none`, so it could not be clicked, and its only job was a `::before` spacer that `scroll-margin-top` on the heading already does. Being an `<a href>` it stayed in the tab order, so every heading was an unexplained keyboard stop: eight on the installation page alone. Fragment navigation still lands 112px down, clear of the fixed header. * Harden the site image build and its CI The architecture guard could not fire. `${TARGETARCH:-amd64}` defaulted before the `unsupported arch` branch was reachable, so a build without buildkit put an amd64 hugo inside an aarch64 image and ran only because Docker Desktop emulates it. Reproduced with `--build-arg TARGETARCH=`: `/etc/apk/arch` reported aarch64 and `hugo version` linux/amd64. An empty value is an error now. `Dockerfile.dev` had the same defect and no smoke step to catch it, so it would have failed at `compose up`. The hugo tarball is verified against the release's own `checksums.txt`, and the match is asserted present before it is used: piping grep straight into `sha256sum -c` left the guarantee resting on what the checker does with empty input. Busybox exits 1 there, so it did fail closed, but nothing in the line said so. Verified against a checksums file that does not list the tarball: the build stops before the install. Hugo exits 0 on an empty content tree and emits a two-page shell, which would have been copied, pushed and deployed. The build asserts the home page and a docs page exist. `site/**` pull requests were never built. The only building job is gated on `github.ref == 'refs/heads/master'`, so on a pull request every job skipped and rendered in the checks list the same way a pass does, and the image was first built on the run that also deploys it. A `validate` job builds it with `push: false`, needing no secrets so it works on a fork. `.github/dependabot.yml` watched `/site` for npm packages that are gone. That entry is a docker one, which tracks the alpine base. It does not track the hugo pin and cannot: the docker ecosystem reads `FROM` references, and `ARG HUGO_VERSION` is a bare string in a download URL, so that one is a manual bump and `site/README.md` says so. `Dockerfile.dev` carries a `COPY`, so the dev image works without the compose bind mount, and compose runs as the invoking user rather than root, which on linux left root-owned `public/` and `resources/` in the checkout. Recorded in the backlog: `master` has `required_status_checks` off with an empty check list, so the new job surfaces a red X and does not block a merge. That is a settings decision rather than a code fix. |
||
|
|
43fccf3bc9 |
chore(deps): bump the github-actions-updates group across 1 directory with 3 updates
Bumps the github-actions-updates group with 3 updates in the / directory: [actions/setup-go](https://github.com/actions/setup-go), [pnpm/action-setup](https://github.com/pnpm/action-setup) and [actions/setup-node](https://github.com/actions/setup-node). Updates `actions/setup-go` from 6 to 7 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v6...v7) Updates `pnpm/action-setup` from 6.0.9 to 6.0.10 - [Release notes](https://github.com/pnpm/action-setup/releases) - [Commits](https://github.com/pnpm/action-setup/compare/v6.0.9...v6.0.10) Updates `actions/setup-node` from 6 to 7 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions-updates - dependency-name: actions/setup-node dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions-updates - dependency-name: pnpm/action-setup dependency-version: 6.0.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions-updates ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
455d770899 |
ci: track the latest Go 1.25 patch instead of pinning one (#2156)
govulncheck fails on master against the 1.25.12 pin with seven stdlib
advisories, all fixed in 1.25.13: GO-2026-5026, GO-2026-5972, GO-2026-6088,
GO-2026-6089, GO-2026-6090, GO-2026-6091 and GO-2026-6218, across crypto/tls,
encoding/asn1, encoding/xml, html/template, net/http and net/url.
Pinning the next patch would only move the problem to the following advisory,
as it did in
|
||
|
|
76d0cc2cf6 |
fix(ci): pin go-version to 1.25.12 for GO-2026-5856
setup-go with go-version "1.25" resolved to 1.25.11, which govulncheck flags for GO-2026-5856 (ECH privacy leak in crypto/tls, fixed in go1.25.12). Pin the exact patch in ci-backend.yml and release.yml so the vuln scan passes and release binaries build on the fixed toolchain. |
||
|
|
8318f89dde |
chore(deps): bump the github-actions-updates group across 1 directory with 4 updates
Bumps the github-actions-updates group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/cache](https://github.com/actions/cache), [pnpm/action-setup](https://github.com/pnpm/action-setup) and [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `actions/checkout` from 6 to 7 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) Updates `actions/cache` from 5 to 6 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v5...v6) Updates `pnpm/action-setup` from 6.0.4 to 6.0.9 - [Release notes](https://github.com/pnpm/action-setup/releases) - [Commits](https://github.com/pnpm/action-setup/compare/v6.0.4...v6.0.9) Updates `codecov/codecov-action` from 6 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions-updates - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions-updates - dependency-name: pnpm/action-setup dependency-version: 6.0.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions-updates - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions-updates ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
4baf0f4260 |
Close remaining node/pnpm version drift after the pnpm 10 bump
- frontend/.nvmrc was still pinned to 16, left behind by the node 16->20 bump everywhere else (Dockerfile, CI matrices). A contributor running 'nvm use' in frontend/ would land on node 16, which cannot even run pnpm 10 (requires node >=18) -- CI never reads .nvmrc, so this was invisible to every check. - pnpm/action-setup 'version: 10' floated the patch release in CI, inconsistent with the exact 10.10.0 pin now used in Dockerfile, Dockerfile.e2e and packageManager. Pinned all ten occurrences across ci-frontend.yml, ci-frontend-api.yml and release.yml to 10.10.0. |
||
|
|
8626e4181f |
Fix CI for node 20 / pnpm 10: e2e Playwright image and jest arg forwarding
- frontend/Dockerfile.e2e: bump base image to mcr.microsoft.com/playwright: v1.61.1-noble to match the Playwright 1.61.1 npm bump (browser revision mismatch was failing all e2e specs), and corepack pnpm@8 -> pnpm@10.10.0 to match the pnpm bump and the v9 lockfile. - release.yml validate: pnpm 10 forwards 'test -- --runInBand' literally as 'jest -- --runInBand' (treated as a path pattern, 0 tests). Drop the extra separator: 'pnpm test --runInBand'. |
||
|
|
f5ccfaa0e1 |
Update frontend dependencies to latest, bump pnpm to 10, clear all npm audit alerts
pnpm 8.15.9 -> 10.10.0 (packageManager + lockfile regenerated to v9). Frontend CI (ci-frontend.yml, ci-frontend-api.yml, release.yml) and the production Dockerfile bumped from node 16 + pnpm 8 to node 20 + pnpm 10 (pnpm 10 requires node 18+). pnpm audit: no known vulnerabilities (was 63 alerts). packages/api: bumped to latest including the major test stack - vitest 4, jsdom 29, @vitest/coverage-v8 4, @typescript-eslint 8.62, typescript 5.9, prettier 3.9, @types/node 26, and msw 1 -> 2. Migrated tests/test-utils.ts to the msw 2 http/HttpResponse API (capturing a compatible request shape) and made test base URLs absolute so node 20's native fetch is intercepted; added the jsdom base URL. type-check:api, lint:api and coverage:api (45 tests) all pass. apps/remark42: safe in-major bumps (webpack 5.108, postcss, mini-css-extract, html-webpack-plugin, ts-loader, webpack-dev-server 5.2.5, core-js, clsx 2, lodash-es 4.18, dotenv 17, @types/*). Transitive vulns patched via pnpm.overrides. type-check, lint, build, jest coverage (299 tests) and translations all pass. pnpm 10's stricter layout required a few pins to keep the app's preact-compat setup compiling: preact 10.6.2 (override), react-intl 6.0.5 and @testing-library/preact 3.2.2 (newer types break the build), tsconfig paths for preact, @types/minimatch 5.1.2 (6.x is an empty stub) and cheerio 1.0.0-rc.12 (1.2 is ESM and breaks jest 28). Held: react/react-dom (preact compat alias), babel 7, eslint 8, stylelint 14, jest 28, typescript 4.7 (app), redux/react-redux - majors that change the bundle or need a config migration. Build output verified against a clean master build: apps/remark42 output is functionally identical (the only diffs are webpack module-id numbering and css-module class tokens from the webpack/css-loader bump; all HTML, CSS values and translations byte-identical). |
||
|
|
556e0a70d5 |
chore(release): build binary artifacts with GoReleaser (#2070)
replace the Docker artifact build with GoReleaser config and a tag release workflow. Keep local artifact builds snapshot-only and clean generated frontend embed files after release runs. |