Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ build-types
.env
.env.local
.env.*.local
/vendor/*/node_modules
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ See [docs/spec.md](docs/spec.md) for the full architecture documentation (contex

- `app/` - application code
- `docs/` - architecture documentation (`spec.md`)
- `scripts/` - build helpers (`build:prod`)
- `vendor/secvisogram-editor/` - pinned `@secvisogram/editor` install, kept out of the main `npm ci`
- `secvisogram-mock/` - dev-only stub of the `<secvisogram-editor>` custom element, loaded only in `npm run dev` so the app is runnable without the real `secvisogram-editor.js` bundle present

## Getting started
Expand All @@ -34,12 +36,32 @@ Requires Node 24 (see `.nvmrc`).
```sh
npm install
npm run dev # start the Vite dev server
npm run build # production build (static assets under build/client)
npm run build # production build (static assets under build/client), no editor
npm run build:prod # build + real editor tree in build/client/secvisogram-editor (see below)
npm run typecheck # generate route types and run tsc
npm run lint # oxlint
npm run format:check # oxfmt --check
```

## Real editor in production builds

`npm run build:prod` loads the real editor, a `-demo.N` prerelease of `@secvisogram/editor` from the GitHub Packages npm registry. It is installed separately from the main dependencies, so `npm ci` and `npm run build` need no token.

Log in once to GitHub Packages. Use your GitHub username and a personal access token (classic) with `read:packages` as the password; npm stores the token in `~/.npmrc`, outside the repository:

```sh
npm login --registry https://npm.pkg.github.com
```

Then install the editor and build:

```sh
cd vendor/secvisogram-editor && npm ci && cd ../..
npm run build:prod
```

`build:prod` fails before building if the editor is not installed. It copies the package's `dist/` to `build/client/secvisogram-editor/`.

## Testing

```sh
Expand Down
30 changes: 30 additions & 0 deletions app/EditorScript.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { render } from 'vitest-browser-react'

import { EditorScript } from './EditorScript'

const EDITOR_SELECTOR =
'script[src="/secvisogram-editor/secvisogram-editor.js"]'

afterEach(() => {
vi.unstubAllEnvs()
})

describe('EditorScript', () => {
it('emits the deferred classic editor script in production-editor builds', async () => {
vi.stubEnv('VITE_EMBED_EDITOR', 'true')

await render(<EditorScript />)

const script = document.querySelector<HTMLScriptElement>(EDITOR_SELECTOR)
expect(script).not.toBeNull()
expect(script?.defer).toBe(true)
expect(script?.type).not.toBe('module')
})

it('emits nothing when the build constant is not set', async () => {
await render(<EditorScript />)

expect(document.querySelector(EDITOR_SELECTOR)).toBeNull()
})
})
6 changes: 6 additions & 0 deletions app/EditorScript.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function EditorScript() {
// `VITE_EMBED_EDITOR` is set only by `build:prod`.
return import.meta.env.VITE_EMBED_EDITOR === 'true' ? (
<script defer src="/secvisogram-editor/secvisogram-editor.js"></script>
) : null
}
3 changes: 3 additions & 0 deletions app/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
interface ImportMetaEnv {
readonly VITE_EMBED_EDITOR?: string
}
2 changes: 2 additions & 0 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next'

import { AppConfigError, getAppConfig } from '~/auth/appConfig'
import { fetchApiOrRedirect } from '~/auth/session'
import { EditorScript } from '~/EditorScript'
import '~/i18n/i18n'
import { NotificationProvider } from '~/notifications/NotificationContext'
import type { Route } from './+types/root'
Expand Down Expand Up @@ -46,6 +47,7 @@ export function Layout({ children }: { children: React.ReactNode }) {
{children}
<ScrollRestoration />
<Scripts />
<EditorScript />
</body>
</html>
)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"scripts": {
"dev": "react-router dev",
"build": "react-router build && rm -r build/client/secvisogram-mock",
"build:prod": "node scripts/buildProd.ts",
"typecheck": "react-router typegen && tsc -b .",
"test": "vitest run --project=node",
"test:browser": "vitest run --project=browser",
Expand Down
21 changes: 21 additions & 0 deletions scripts/buildProd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { execFileSync } from 'node:child_process'
import { cp, stat } from 'node:fs/promises'

const editorDist =
'vendor/secvisogram-editor/node_modules/@secvisogram/editor/dist'

if (!(await stat(editorDist).catch(() => null))?.isDirectory()) {
console.error(
`The Secvisogram editor is not installed (missing ${editorDist}). ` +
'Run `npm ci` in vendor/secvisogram-editor first (see README).',
)
process.exitCode = 1
} else {
execFileSync('npm run build', {
stdio: 'inherit',
env: { ...process.env, VITE_EMBED_EDITOR: 'true' },
shell: true,
})

await cp(editorDist, 'build/client/secvisogram-editor', { recursive: true })
}
1 change: 1 addition & 0 deletions vendor/secvisogram-editor/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@secvisogram:registry=https://npm.pkg.github.com
19 changes: 19 additions & 0 deletions vendor/secvisogram-editor/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions vendor/secvisogram-editor/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "secvisogram-editor-vendor",
"private": true,
"description": "Installs the pinned @secvisogram/editor prerelease from GitHub Packages; copied into build/client by build:prod.",
"dependencies": {
"@secvisogram/editor": "0.1.0-demo.1"
}
}
Loading