Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5dc9b2c6d |
13
README.md
13
README.md
@@ -3,9 +3,11 @@
|
|||||||
A Nuxt 4 layer that renders a Journal blog (post list, post, category, tag and author pages, RSS link) from the Journal API of a SummerCMS application, with its SEO output from the CMS through vue-seo-layer.
|
A Nuxt 4 layer that renders a Journal blog (post list, post, category, tag and author pages, RSS link) from the Journal API of a SummerCMS application, with its SEO output from the CMS through vue-seo-layer.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm add git+https://git.golem15.com/golem15/vue-journal-layer.git#v0.8.0
|
pnpm add git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0 git+https://git.golem15.com/golem15/vue-journal-layer.git#v0.8.1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
vue-seo-layer is a peer dependency (`^0.2.0`): the app lists it next to the layer, pinned to a tag as above, and needs no `extends` entry for it (the layer extends it). The layer cannot bring it itself: pnpm refuses a git dependency inside another package (`blockExoticSubdeps`, on by default).
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The layer is consumed with `extends: ['vue-journal-layer']`. It reads content only from the anonymous GET routes of the Journal API (`/_journal/api/v1`) and never calls a write route. Pages render on the server (SSR), so every URL answers with full HTML.
|
The layer is consumed with `extends: ['vue-journal-layer']`. It reads content only from the anonymous GET routes of the Journal API (`/_journal/api/v1`) and never calls a write route. Pages render on the server (SSR), so every URL answers with full HTML.
|
||||||
@@ -83,7 +85,7 @@ export default defineNuxtConfig({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
The layer declares `@nuxt/fonts`, `@nuxtjs/i18n`, `sanitize-html` and `vue-seo-layer` itself. Do not list them again in the app; if the app must, pin the same exact versions. Static app pages such as `/about` take precedence over a `/:category` route.
|
The layer declares `@nuxt/fonts`, `@nuxtjs/i18n` and `sanitize-html` itself. Do not list them again in the app; if the app must, pin the same exact versions. `vue-seo-layer` is a peer dependency: the app lists it (`"vue-seo-layer": "git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0"`). Static app pages such as `/about` take precedence over a `/:category` route.
|
||||||
|
|
||||||
Run the built app with `node .output/server/index.mjs` next to the SummerCMS application and point `NUXT_JOURNAL_API_BASE` (and vue-seo-layer's `NUXT_SEO_API_BASE`) at it. A site without the SEO plugin sets `seo: { cms: false }`; its pages then keep the journal's fallback titles and descriptions.
|
Run the built app with `node .output/server/index.mjs` next to the SummerCMS application and point `NUXT_JOURNAL_API_BASE` (and vue-seo-layer's `NUXT_SEO_API_BASE`) at it. A site without the SEO plugin sets `seo: { cms: false }`; its pages then keep the journal's fallback titles and descriptions.
|
||||||
|
|
||||||
@@ -258,6 +260,7 @@ The feed's item links come from the Journal API, which links posts under `/blog/
|
|||||||
|
|
||||||
## Upgrading from 0.7
|
## Upgrading from 0.7
|
||||||
|
|
||||||
|
- **List vue-seo-layer in the app** (from 0.8.1): `"vue-seo-layer": "git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0"` next to `vue-journal-layer#v0.8.1`. It is a peer dependency of the layer (`^0.2.0`). 0.8.0 listed it as its own git dependency, which pnpm refuses by default (`ERR_PNPM_EXOTIC_SUBDEP`), so use 0.8.1.
|
||||||
- **`@nuxtjs/seo` is gone.** The layer extends vue-seo-layer instead. Remove `site: { url, name }` and the `ogImage`, `seo.canonicalQueryWhitelist`, `sitemap`, `robots` and `schemaOrg` keys that only `@nuxtjs/seo` read; set `NUXT_SEO_API_BASE` (the SEO plugin, default `http://127.0.0.1:8096/_seo/api/v1`) or `seo: { cms: false }` for a site without the SEO plugin. `useSiteConfig()`, `useSchemaOrg()` and the other `@nuxtjs/seo` composables are no longer available to the app through this layer; an app that uses them adds `@nuxtjs/seo` itself (then it emits its own canonical and graph next to the CMS's) or moves to the CMS answer.
|
- **`@nuxtjs/seo` is gone.** The layer extends vue-seo-layer instead. Remove `site: { url, name }` and the `ogImage`, `seo.canonicalQueryWhitelist`, `sitemap`, `robots` and `schemaOrg` keys that only `@nuxtjs/seo` read; set `NUXT_SEO_API_BASE` (the SEO plugin, default `http://127.0.0.1:8096/_seo/api/v1`) or `seo: { cms: false }` for a site without the SEO plugin. `useSiteConfig()`, `useSchemaOrg()` and the other `@nuxtjs/seo` composables are no longer available to the app through this layer; an app that uses them adds `@nuxtjs/seo` itself (then it emits its own canonical and graph next to the CMS's) or moves to the CMS answer.
|
||||||
- **The journal sitemap source is gone** (`/api/__sitemap__/journal`, `buildJournalSitemapEntries`): the sitemap plugin builds the sitemaps, served through vue-seo-layer.
|
- **The journal sitemap source is gone** (`/api/__sitemap__/journal`, `buildJournalSitemapEntries`): the sitemap plugin builds the sitemaps, served through vue-seo-layer.
|
||||||
- **The shared purge route moved** to vue-seo-layer, with the same path, contract and variables; `server/lib/siteCachePurge.ts`, `server/api/__site__/cache/purge.post.ts` and `server/plugins/site-cache-purge.ts` are no longer in this layer. The deprecated `POST /api/__journal__/cache/purge` keeps working.
|
- **The shared purge route moved** to vue-seo-layer, with the same path, contract and variables; `server/lib/siteCachePurge.ts`, `server/api/__site__/cache/purge.post.ts` and `server/plugins/site-cache-purge.ts` are no longer in this layer. The deprecated `POST /api/__journal__/cache/purge` keeps working.
|
||||||
@@ -283,16 +286,16 @@ To work on the layer inside an app, link it instead of installing from git: `pnp
|
|||||||
|
|
||||||
A release is an annotated git tag (`v0.1.0`) on `main`, pushed to git.golem15.com. Apps pin it in `package.json` as `git+https://git.golem15.com/golem15/vue-journal-layer.git#<tag>`, and `pnpm-lock.yaml` records the tag's commit. To upgrade, change the tag and run `pnpm install`. The repository is public, so installing needs no credentials. The layer has no install-time build or `prepare` script, which a git-hosted dependency would need to run during `pnpm install`.
|
A release is an annotated git tag (`v0.1.0`) on `main`, pushed to git.golem15.com. Apps pin it in `package.json` as `git+https://git.golem15.com/golem15/vue-journal-layer.git#<tag>`, and `pnpm-lock.yaml` records the tag's commit. To upgrade, change the tag and run `pnpm install`. The repository is public, so installing needs no credentials. The layer has no install-time build or `prepare` script, which a git-hosted dependency would need to run during `pnpm install`.
|
||||||
|
|
||||||
A content layer (this one, vue-menu-layer, vue-faq-layer) extends vue-seo-layer through its `vue-seo-layer` dependency, which points at the local checkout (`link:../vue-seo-layer`) during development. A tag cut with that link breaks every git install: the path resolves next to the pnpm store entry, not to a package. Before tagging any content layer:
|
A content layer (this one, vue-menu-layer, vue-faq-layer) extends vue-seo-layer, declared as a peer dependency (`"vue-seo-layer": "^0.2.0"`, which the app provides) and as a development dependency for the playground and the tests. The development dependency may point at the local checkout (`link:../vue-seo-layer`) while both change together; a tag cut with that link breaks every git install, because the path resolves next to the pnpm store entry, not to a package. vue-seo-layer is never a regular dependency of a content layer: pnpm refuses a git dependency inside another package (`blockExoticSubdeps`). Before tagging any content layer:
|
||||||
|
|
||||||
1. Tag vue-seo-layer first, then in each content layer replace the link with the tag pin (`"vue-seo-layer": "git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0"`) and run `pnpm install`, so `pnpm-lock.yaml` records the seo layer's commit.
|
1. Tag vue-seo-layer first, then in each content layer set the development dependency to the tag pin (`"vue-seo-layer": "git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0"`), the peer range to match, and run `pnpm install`, so `pnpm-lock.yaml` records the seo layer's commit.
|
||||||
2. Run `bash scripts/check-git-install.sh --check-links ../vue-seo-layer ../vue-journal-layer ../vue-menu-layer ../vue-faq-layer`. It fails while any of those `package.json` files has a `link:`, `file:`, `workspace:` or `portal:` dependency, and names each one.
|
2. Run `bash scripts/check-git-install.sh --check-links ../vue-seo-layer ../vue-journal-layer ../vue-menu-layer ../vue-faq-layer`. It fails while any of those `package.json` files has a `link:`, `file:`, `workspace:` or `portal:` dependency, and names each one.
|
||||||
3. Tag and push, then run `bash scripts/check-git-install.sh <tag>`, which repeats the check on the installed tag before building.
|
3. Tag and push, then run `bash scripts/check-git-install.sh <tag>`, which repeats the check on the installed tag before building.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
- `pnpm test` runs the unit tests in `tests/*.test.ts` with `node --test` (Node strips the TypeScript types; no test framework dependency). They cover the pure helpers in `app/utils/`: route normalization and path filling, the client against a fake fetcher (including the suggest query), the search helpers (term rules, diacritic-insensitive marking, plural forms, combobox keys, and the suggestion controller's debounce, abort and stale-answer handling under mocked timers), pagination, the HTML sanitizer (the Journal plugin's FormatHTML cases, the bypasses from its code review, and the Blog Editor corpus in `tests/fixtures/editor-corpus.json`, a byte copy of the plugin's), the H1 demotion and the body pipeline order, the featured image srcsets (`tests/srcset.test.ts`), the embed expansion and its sanitize-first order, the post page view, SEO values (fallback meta, the title element, ItemList), path-form routes, the old purge route's helpers and browser revalidation (`tests/siteCache.test.ts`), and pl/en key and placeholder parity. The shared purge route and the body link steps are tested in vue-seo-layer. They need no build, network or database.
|
- `pnpm test` runs the unit tests in `tests/*.test.ts` with `node --test` (Node strips the TypeScript types; no test framework dependency). They cover the pure helpers in `app/utils/`: route normalization and path filling, the client against a fake fetcher (including the suggest query), the search helpers (term rules, diacritic-insensitive marking, plural forms, combobox keys, and the suggestion controller's debounce, abort and stale-answer handling under mocked timers), pagination, the HTML sanitizer (the Journal plugin's FormatHTML cases, the bypasses from its code review, and the Blog Editor corpus in `tests/fixtures/editor-corpus.json`, a byte copy of the plugin's), the H1 demotion and the body pipeline order, the featured image srcsets (`tests/srcset.test.ts`), the embed expansion and its sanitize-first order, the post page view, SEO values (fallback meta, the title element, ItemList), path-form routes, the old purge route's helpers and browser revalidation (`tests/siteCache.test.ts`), and pl/en key and placeholder parity. The shared purge route and the body link steps are tested in vue-seo-layer. They need no build, network or database.
|
||||||
- `scripts/check-git-install.sh <tag>` installs the layer from the git tag into a scratch app built from the layer's playground config (`.playground/nuxt.config.ts` extending the installed layer, and its `app.vue`), checks that `pnpm-lock.yaml` pins the tag's commit for vue-journal-layer (its own git dependencies, such as vue-seo-layer, are ignored), checks that the installed `package.json` has no local dependency, runs `nuxt build`, and runs the SSR smoke against the build. `--check-links DIR...` checks the `package.json` of each directory for `link:`, `file:`, `workspace:` and `portal:` dependencies (the release guard, see [Releasing](#releasing)). `--self-test` checks the lockfile reading and the link check on planted files. Run it from a directory that is not inside a directory named `vue-journal-layer` (Nuxt treats such a path segment as the layer).
|
- `scripts/check-git-install.sh <tag>` installs the layer from the git tag, next to vue-seo-layer at the tag's development pin (`SEO_LAYER_SPEC` overrides it), with pnpm's default settings, into a scratch app built from the layer's playground config (`.playground/nuxt.config.ts` extending the installed layer, and its `app.vue`), checks that `pnpm-lock.yaml` pins the tag's commit for vue-journal-layer (its own git dependencies, such as vue-seo-layer, are ignored), checks that the installed `package.json` has no local dependency, runs `nuxt build`, and runs the SSR smoke against the build. `--check-links DIR...` checks the `package.json` of each directory for `link:`, `file:`, `workspace:` and `portal:` dependencies (the release guard, see [Releasing](#releasing)). `--self-test` checks the lockfile reading and the link check on planted files. Run it from a directory that is not inside a directory named `vue-journal-layer` (Nuxt treats such a path segment as the layer).
|
||||||
- `testing/smoke-ssr.mjs --output <.output> --fixtures <dir> --expect <file> [--env KEY=VALUE]...` boots a fixture Journal and SEO API and the built server and checks each line of the expectations file: `STATUS PATH [contains=TEXT] [notcontains=TEXT] [count=TEXT:N] [type=PREFIX] [header=NAME: VALUE] [noheader=NAME] [headings=strict] [cardlinks=N]`, every option repeatable, and `resolves PATH N` (the SEO resolve calls so far for a path, `*` for all). `headings=strict` wants exactly one `<h1` and no skipped level, `cardlinks=N` exactly N links in each post card. It also checks that SSR requests forwarded `x-forwarded-for` and that categories were requested with `include_empty=1`. `pnpm smoke:ssr` runs `expect-acme.txt` and the expectation files for `postTitleTag` forced to `h1` and `p`, the new-tab hint off and `journal.breadcrumbs` off.
|
- `testing/smoke-ssr.mjs --output <.output> --fixtures <dir> --expect <file> [--env KEY=VALUE]...` boots a fixture Journal and SEO API and the built server and checks each line of the expectations file: `STATUS PATH [contains=TEXT] [notcontains=TEXT] [count=TEXT:N] [type=PREFIX] [header=NAME: VALUE] [noheader=NAME] [headings=strict] [cardlinks=N]`, every option repeatable, and `resolves PATH N` (the SEO resolve calls so far for a path, `*` for all). `headings=strict` wants exactly one `<h1` and no skipped level, `cardlinks=N` exactly N links in each post card. It also checks that SSR requests forwarded `x-forwarded-for` and that categories were requested with `include_empty=1`. `pnpm smoke:ssr` runs `expect-acme.txt` and the expectation files for `postTitleTag` forced to `h1` and `p`, the new-tab hint off and `journal.breadcrumbs` off.
|
||||||
- `testing/purge-check.mjs --output <.output> --fixtures <dir> --kind post|category --slug <slug> --path <page path>` proves the [site cache purge](#site-cache-purge) on a built server whose route rules cache pages: it caches the page, changes the entity in a temporary copy of the fixtures, requires the cached page to stay unchanged, purges with a random token, and requires the change on the next request. It also checks `max-age=0` on the page and its 304, the purged `_payload.json`, a second purge after re-caching, `401` without or with a wrong token, `404` behind a proxy and `404` on a server without a token. The last line is `purge-check: ok (<n> checks)`.
|
- `testing/purge-check.mjs --output <.output> --fixtures <dir> --kind post|category --slug <slug> --path <page path>` proves the [site cache purge](#site-cache-purge) on a built server whose route rules cache pages: it caches the page, changes the entity in a temporary copy of the fixtures, requires the cached page to stay unchanged, purges with a random token, and requires the change on the next request. It also checks `max-age=0` on the page and its 304, the purged `_payload.json`, a second purge after re-caching, `401` without or with a wrong token, `404` behind a proxy and `404` on a server without a token. The last line is `purge-check: ok (<n> checks)`.
|
||||||
- `testing/purge-token-check.mjs --output <.output> --fixtures <dir> --path <page path>` proves on a built server that the purge token never reaches a page. It starts the server three times with fresh random tokens: under `NUXT_CACHE_PURGE_TOKEN`, under the deprecated `NUXT_SITE_CACHE_PURGE_TOKEN` with `NUXT_SITE_CACHE_ALLOW_PROXIED=true`, and under both names with different values. Each time `/`, the page and its `_payload.json` (when served) must contain no token value and neither `cachePurgeToken` nor `cacheAllowProxied`, the shared purge route must accept the expected bearer and refuse the others, and the deprecation warning must appear once with the old names only. The last line is `purge-token-check: ok (<n> checks)`.
|
- `testing/purge-token-check.mjs --output <.output> --fixtures <dir> --path <page path>` proves on a built server that the purge token never reaches a page. It starts the server three times with fresh random tokens: under `NUXT_CACHE_PURGE_TOKEN`, under the deprecated `NUXT_SITE_CACHE_PURGE_TOKEN` with `NUXT_SITE_CACHE_ALLOW_PROXIED=true`, and under both names with different values. Each time `/`, the page and its `_payload.json` (when served) must contain no token value and neither `cachePurgeToken` nor `cacheAllowProxied`, the shared purge route must accept the expected bearer and refuse the others, and the deprecation warning must appear once with the old names only. The last line is `purge-token-check: ok (<n> checks)`.
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-journal-layer",
|
"name": "vue-journal-layer",
|
||||||
"version": "0.8.0",
|
"version": "0.8.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./nuxt.config.ts",
|
"main": "./nuxt.config.ts",
|
||||||
@@ -18,16 +18,17 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/fonts": "0.14.0",
|
"@nuxt/fonts": "0.14.0",
|
||||||
"@nuxtjs/i18n": "10.4.0",
|
"@nuxtjs/i18n": "10.4.0",
|
||||||
"sanitize-html": "2.18.0",
|
"sanitize-html": "2.18.0"
|
||||||
"vue-seo-layer": "git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"nuxt": "4.4.8"
|
"nuxt": "4.4.8",
|
||||||
|
"vue-seo-layer": "^0.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/sanitize-html": "2.16.2",
|
"@types/sanitize-html": "2.16.2",
|
||||||
"nuxt": "4.4.8",
|
"nuxt": "4.4.8",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
"vue": "3.5.35"
|
"vue": "3.5.35",
|
||||||
|
"vue-seo-layer": "git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -17,9 +17,6 @@ importers:
|
|||||||
sanitize-html:
|
sanitize-html:
|
||||||
specifier: 2.18.0
|
specifier: 2.18.0
|
||||||
version: 2.18.0
|
version: 2.18.0
|
||||||
vue-seo-layer:
|
|
||||||
specifier: git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0
|
|
||||||
version: git+https://git.golem15.com/golem15/vue-seo-layer.git#3868f3d74dcebb7a35af43f1defcd68cfe2933b7(nuxt@4.4.8(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2)))(@oxc-project/types@0.133.0)(@types/node@26.6.4)(@vue/compiler-sfc@3.5.43)(cac@6.7.14)(confbox@0.3.1)(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.12.0(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.64.2))(rollup@4.64.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.7(@types/node@26.6.4)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1))
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/sanitize-html':
|
'@types/sanitize-html':
|
||||||
specifier: 2.16.2
|
specifier: 2.16.2
|
||||||
@@ -33,6 +30,9 @@ importers:
|
|||||||
vue:
|
vue:
|
||||||
specifier: 3.5.35
|
specifier: 3.5.35
|
||||||
version: 3.5.35(typescript@5.9.3)
|
version: 3.5.35(typescript@5.9.3)
|
||||||
|
vue-seo-layer:
|
||||||
|
specifier: git+https://git.golem15.com/golem15/vue-seo-layer.git#v0.2.0
|
||||||
|
version: git+https://git.golem15.com/golem15/vue-seo-layer.git#3868f3d74dcebb7a35af43f1defcd68cfe2933b7(nuxt@4.4.8(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@10.2.2)))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2)))(@oxc-project/types@0.133.0)(@types/node@26.6.4)(@vue/compiler-sfc@3.5.43)(cac@6.7.14)(confbox@0.3.1)(db0@0.3.4)(dotenv@17.4.2)(esbuild@0.28.2)(eslint@10.12.0(jiti@2.7.0)(supports-color@10.2.2))(giget@3.3.1)(ioredis@5.11.1(supports-color@10.2.2))(lightningcss@1.33.0)(magicast@0.5.5)(optionator@0.9.4)(rollup-plugin-visualizer@7.1.1(rollup@4.64.2))(rollup@4.64.2)(srvx@0.11.22)(supports-color@10.2.2)(terser@5.51.2)(typescript@5.9.3)(vite@7.3.7(@types/node@26.6.4)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.51.2)(yaml@2.9.1))(yaml@2.9.1))
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
#
|
#
|
||||||
# Proves the layer's distribution end to end: a scratch app installs
|
# Proves the layer's distribution end to end: a scratch app installs
|
||||||
# vue-journal-layer from git+https://git.golem15.com/golem15/vue-journal-layer.git#<tag>
|
# vue-journal-layer from git+https://git.golem15.com/golem15/vue-journal-layer.git#<tag>
|
||||||
# anonymously, the installed package.json has no local dependency, the
|
# anonymously, next to vue-seo-layer (a peer dependency, listed by the app at
|
||||||
|
# the tag's devDependencies pin) with pnpm's default settings, the installed package.json has no local dependency, the
|
||||||
# lockfile pins the tag's commit, `nuxt build` of the layer's playground
|
# lockfile pins the tag's commit, `nuxt build` of the layer's playground
|
||||||
# config succeeds, and the built server passes testing/expect-acme.txt
|
# config succeeds, and the built server passes testing/expect-acme.txt
|
||||||
# against the fixture API.
|
# against the fixture API.
|
||||||
@@ -144,20 +145,36 @@ TAG_SHA="$(awk -v ref="refs/tags/$TAG^{}" '$2 == ref { print $1 }' <<<"$REMOTE_R
|
|||||||
[[ -n "$TAG_SHA" ]] || TAG_SHA="$(awk -v ref="refs/tags/$TAG" '$2 == ref { print $1 }' <<<"$REMOTE_REFS")"
|
[[ -n "$TAG_SHA" ]] || TAG_SHA="$(awk -v ref="refs/tags/$TAG" '$2 == ref { print $1 }' <<<"$REMOTE_REFS")"
|
||||||
[[ -n "$TAG_SHA" ]] || die "tag $TAG not found on $REPO_URL"
|
[[ -n "$TAG_SHA" ]] || die "tag $TAG not found on $REPO_URL"
|
||||||
|
|
||||||
|
# vue-seo-layer is a peer dependency of the layer, so an app lists it next to
|
||||||
|
# the layer, as the README's Installation says. The scratch app takes the
|
||||||
|
# spec the tag pins for its own development (devDependencies), or
|
||||||
|
# SEO_LAYER_SPEC when set. A tag that still lists vue-seo-layer under
|
||||||
|
# dependencies (v0.8.0) gets none: pnpm then refuses it as an exotic
|
||||||
|
# subdependency, which is what this check is for.
|
||||||
|
SEO_SPEC="${SEO_LAYER_SPEC:-}"
|
||||||
|
if [[ -z "$SEO_SPEC" ]]; then
|
||||||
|
SRC="$(mktemp -d "${TMPDIR:-/tmp}/journal-git-install-src.XXXXXX")"
|
||||||
|
GIT_TERMINAL_PROMPT=0 git clone --quiet --depth 1 --branch "$TAG" "$REPO_URL" "$SRC/layer" 2>/dev/null \
|
||||||
|
|| { rm -rf "$SRC"; die "git clone of $TAG failed"; }
|
||||||
|
SEO_SPEC="$(node -e '
|
||||||
|
const pkg = JSON.parse(require("node:fs").readFileSync(process.argv[1], "utf8"))
|
||||||
|
const peer = (pkg.peerDependencies || {})["vue-seo-layer"]
|
||||||
|
const dev = (pkg.devDependencies || {})["vue-seo-layer"]
|
||||||
|
process.stdout.write(peer && dev ? dev : "")
|
||||||
|
' "$SRC/layer/package.json")" || { rm -rf "$SRC"; die "cannot read the tag's package.json"; }
|
||||||
|
rm -rf "$SRC"
|
||||||
|
fi
|
||||||
|
|
||||||
cd "$WORK"
|
cd "$WORK"
|
||||||
|
|
||||||
cat >package.json <<JSON
|
node -e '
|
||||||
{
|
const [repo, tag, seo] = process.argv.slice(1)
|
||||||
"name": "acme-blog",
|
const deps = { nuxt: "4.4.8", vue: "3.5.35" }
|
||||||
"private": true,
|
if (seo) deps["vue-seo-layer"] = seo
|
||||||
"type": "module",
|
deps["vue-journal-layer"] = `git+${repo}#${tag}`
|
||||||
"dependencies": {
|
const pkg = { name: "acme-blog", private: true, type: "module", dependencies: deps }
|
||||||
"nuxt": "4.4.8",
|
require("node:fs").writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n")
|
||||||
"vue": "3.5.35",
|
' "$REPO_URL" "$TAG" "$SEO_SPEC"
|
||||||
"vue-journal-layer": "git+$REPO_URL#$TAG"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JSON
|
|
||||||
|
|
||||||
cat >pnpm-workspace.yaml <<'YAML'
|
cat >pnpm-workspace.yaml <<'YAML'
|
||||||
allowBuilds:
|
allowBuilds:
|
||||||
|
|||||||
Reference in New Issue
Block a user