livemark 0.13.1 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/Layout.js +3 -2
- package/build/components/SidebarArticles.js +10 -12
- package/build/components/SidebarLinks.js +3 -2
- package/build/components/SiteTitle.js +3 -2
- package/build/content-collections.js +3 -2
- package/build/helpers/prefix-url.d.ts +6 -0
- package/build/helpers/prefix-url.js +24 -0
- package/build/helpers/prefix-url.unit.d.ts +1 -0
- package/build/helpers/prefix-url.unit.js +45 -0
- package/build/helpers/resolve-asset-path.d.ts +1 -1
- package/build/helpers/resolve-asset-path.js +9 -5
- package/build/helpers/resolve-asset-path.unit.d.ts +1 -0
- package/build/helpers/resolve-asset-path.unit.js +34 -0
- package/build/models/config.d.ts +3 -0
- package/build/models/config.js +11 -1
- package/build/plugins/remark-image.d.ts +1 -0
- package/build/plugins/remark-image.js +3 -3
- package/build/plugins/vite-livemark.js +6 -1
- package/build/router.js +3 -1
- package/build/routes/__root.js +3 -2
- package/build/vite.config.js +18 -4
- package/package.json +1 -1
- package/source/components/Layout.tsx +2 -1
- package/source/components/SidebarArticles.tsx +34 -30
- package/source/components/SidebarLinks.tsx +2 -1
- package/source/components/SiteTitle.tsx +2 -1
- package/source/content-collections.ts +2 -1
- package/source/helpers/prefix-url.ts +22 -0
- package/source/helpers/prefix-url.unit.ts +57 -0
- package/source/helpers/resolve-asset-path.ts +12 -5
- package/source/helpers/resolve-asset-path.unit.ts +59 -0
- package/source/models/config.ts +9 -0
- package/source/plugins/remark-image.ts +3 -3
- package/source/plugins/vite-livemark.ts +5 -0
- package/source/router.tsx +2 -0
- package/source/routes/__root.tsx +5 -1
- package/source/vite.config.ts +17 -3
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { dirname, relative, resolve } from "node:path"
|
|
1
|
+
import { dirname, relative, resolve, sep } from "node:path"
|
|
2
|
+
import { prefixUrl } from "./prefix-url.ts"
|
|
2
3
|
|
|
3
4
|
/** Resolve a relative asset path to an absolute URL serveable by Vite */
|
|
4
|
-
export function resolveAssetPath(
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export function resolveAssetPath(
|
|
6
|
+
url: string,
|
|
7
|
+
filePath: string,
|
|
8
|
+
root: string,
|
|
9
|
+
base?: string,
|
|
10
|
+
) {
|
|
11
|
+
if (url.startsWith("http") || url.startsWith("data:")) return url
|
|
12
|
+
if (url.startsWith("/")) return prefixUrl(url, base)
|
|
7
13
|
const absolute = resolve(dirname(filePath), url)
|
|
8
|
-
|
|
14
|
+
const rel = relative(root, absolute).split(sep).join("/")
|
|
15
|
+
return prefixUrl("/" + rel, base)
|
|
9
16
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from "vite-plus/test"
|
|
2
|
+
import { resolveAssetPath } from "./resolve-asset-path.ts"
|
|
3
|
+
|
|
4
|
+
describe("resolveAssetPath", () => {
|
|
5
|
+
const root = "/site"
|
|
6
|
+
const filePath = "/site/docs/page.md"
|
|
7
|
+
|
|
8
|
+
it("should resolve a sibling relative path", () => {
|
|
9
|
+
expect(resolveAssetPath("./logo.png", filePath, root)).toBe(
|
|
10
|
+
"/docs/logo.png",
|
|
11
|
+
)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it("should resolve a parent relative path", () => {
|
|
15
|
+
expect(resolveAssetPath("../assets/x.png", filePath, root)).toBe(
|
|
16
|
+
"/assets/x.png",
|
|
17
|
+
)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("should pass through a root-relative url", () => {
|
|
21
|
+
expect(resolveAssetPath("/foo.png", filePath, root)).toBe("/foo.png")
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it("should pass through an http url", () => {
|
|
25
|
+
expect(resolveAssetPath("https://x.com/y.png", filePath, root)).toBe(
|
|
26
|
+
"https://x.com/y.png",
|
|
27
|
+
)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it("should pass through a data url", () => {
|
|
31
|
+
expect(resolveAssetPath("data:image/png;base64,xyz", filePath, root)).toBe(
|
|
32
|
+
"data:image/png;base64,xyz",
|
|
33
|
+
)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("should prefix a resolved relative path with base", () => {
|
|
37
|
+
expect(resolveAssetPath("./logo.png", filePath, root, "/repo")).toBe(
|
|
38
|
+
"/repo/docs/logo.png",
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it("should prefix a root-relative url with base", () => {
|
|
43
|
+
expect(resolveAssetPath("/foo.png", filePath, root, "/repo")).toBe(
|
|
44
|
+
"/repo/foo.png",
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it("should not double-prefix an already-prefixed url", () => {
|
|
49
|
+
expect(resolveAssetPath("/repo/foo.png", filePath, root, "/repo")).toBe(
|
|
50
|
+
"/repo/foo.png",
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it("should not prefix external urls when base is set", () => {
|
|
55
|
+
expect(
|
|
56
|
+
resolveAssetPath("https://x.com/y.png", filePath, root, "/repo"),
|
|
57
|
+
).toBe("https://x.com/y.png")
|
|
58
|
+
})
|
|
59
|
+
})
|
package/source/models/config.ts
CHANGED
|
@@ -23,6 +23,14 @@ export type UserConfig = Omit<z.infer<typeof UserConfig>, "vite"> & {
|
|
|
23
23
|
}
|
|
24
24
|
export const UserConfig = z.object({
|
|
25
25
|
site: z.string().optional(),
|
|
26
|
+
base: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.transform(v => {
|
|
30
|
+
if (!v) return undefined
|
|
31
|
+
const trimmed = v.replace(/^\/|\/$/g, "")
|
|
32
|
+
return trimmed ? `/${trimmed}` : undefined
|
|
33
|
+
}),
|
|
26
34
|
favicon: z.string().optional(),
|
|
27
35
|
logo: z.string().optional(),
|
|
28
36
|
title: z.string().default("Livemark"),
|
|
@@ -46,6 +54,7 @@ export const WebsiteConfig = UserConfig.pick({
|
|
|
46
54
|
title: true,
|
|
47
55
|
description: true,
|
|
48
56
|
site: true,
|
|
57
|
+
base: true,
|
|
49
58
|
favicon: true,
|
|
50
59
|
logo: true,
|
|
51
60
|
links: true,
|
|
@@ -5,12 +5,12 @@ import { resolveAssetPath } from "../helpers/resolve-asset-path.ts"
|
|
|
5
5
|
|
|
6
6
|
/** Remark plugin that resolves relative image paths and unwraps image-only paragraphs */
|
|
7
7
|
export const remarkImage: Plugin<
|
|
8
|
-
[{ filePath: string; root: string }],
|
|
8
|
+
[{ filePath: string; root: string; base?: string }],
|
|
9
9
|
Root
|
|
10
|
-
> = ({ filePath, root }) => {
|
|
10
|
+
> = ({ filePath, root, base }) => {
|
|
11
11
|
return tree => {
|
|
12
12
|
visit(tree, "image", node => {
|
|
13
|
-
node.url = resolveAssetPath(node.url, filePath, root)
|
|
13
|
+
node.url = resolveAssetPath(node.url, filePath, root, base)
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
visit(tree, "paragraph", (node, index, parent) => {
|
|
@@ -50,6 +50,11 @@ export function livemark(opts: LivemarkOptions): Plugin {
|
|
|
50
50
|
targetDir = buildTarget(opts.config.configPath)
|
|
51
51
|
const base: ViteUserConfig = {
|
|
52
52
|
root: targetDir,
|
|
53
|
+
// Mount everything (asset URLs, modulepreloads, dev server) under
|
|
54
|
+
// `config.base` so the same build works at root or at a sub-path
|
|
55
|
+
// (e.g. GitHub Pages `https://user.github.io/repo/`). The router
|
|
56
|
+
// and asset-path resolver mirror this at runtime.
|
|
57
|
+
base: opts.config.base ? `${opts.config.base}/` : "/",
|
|
53
58
|
// outDir lives outside the target root (in the consumer's
|
|
54
59
|
// .livemark/) so the consumer can find their deployable output
|
|
55
60
|
// without digging into node_modules. Vite's default refusal to
|
package/source/router.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { config } from "livemark:virtual"
|
|
1
2
|
import { QueryClient } from "@tanstack/react-query"
|
|
2
3
|
import { createRouter } from "@tanstack/react-router"
|
|
3
4
|
import { setupRouterSsrQueryIntegration } from "@tanstack/react-router-ssr-query"
|
|
@@ -10,6 +11,7 @@ export function getRouter() {
|
|
|
10
11
|
|
|
11
12
|
const router = createRouter({
|
|
12
13
|
routeTree,
|
|
14
|
+
basepath: config.base,
|
|
13
15
|
context: { queryClient },
|
|
14
16
|
trailingSlash: "always",
|
|
15
17
|
defaultPreload: "intent",
|
package/source/routes/__root.tsx
CHANGED
|
@@ -15,13 +15,17 @@ import { DefaultCatchBoundary } from "../components/DefaultCatchBoundary.tsx"
|
|
|
15
15
|
import { NotFound } from "../components/NotFound.tsx"
|
|
16
16
|
import { Toaster } from "../elements/sonner.tsx"
|
|
17
17
|
import { faviconType } from "../helpers/favicon.ts"
|
|
18
|
+
import { prefixUrl } from "../helpers/prefix-url.ts"
|
|
18
19
|
import defaultFavicon from "../assets/logo.svg"
|
|
19
20
|
import generalCss from "../styles/general.css?url"
|
|
20
21
|
import markdownCss from "../styles/markdown.css?url"
|
|
21
22
|
|
|
22
23
|
export const Route = createRootRoute({
|
|
23
24
|
head: () => {
|
|
24
|
-
const favicon =
|
|
25
|
+
const favicon = prefixUrl(
|
|
26
|
+
config.favicon ?? config.logo ?? defaultFavicon,
|
|
27
|
+
config.base,
|
|
28
|
+
)
|
|
25
29
|
return {
|
|
26
30
|
meta: [
|
|
27
31
|
{ charSet: "utf-8" },
|
package/source/vite.config.ts
CHANGED
|
@@ -18,12 +18,26 @@ export default defineConfig({
|
|
|
18
18
|
contentCollections({ configPath: "content-collections.ts" }),
|
|
19
19
|
tanstackStart({
|
|
20
20
|
srcDirectory: ".",
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// Seed path must match what the crawler produces (router-emitted
|
|
22
|
+
// hrefs include the basepath), otherwise prerender records both
|
|
23
|
+
// shapes and the sitemap ends up with duplicate entries.
|
|
24
|
+
pages: [{ path: config.base ? `${config.base}/` : "/" }],
|
|
25
|
+
// Disable route-tree auto-discovery: it produces basepath-naive
|
|
26
|
+
// paths (e.g. `/`) that duplicate the crawl-derived prefixed paths,
|
|
27
|
+
// bloating pages.json and sitemap. Crawling from the seed already
|
|
28
|
+
// reaches every linked page.
|
|
29
|
+
prerender: {
|
|
30
|
+
enabled: true,
|
|
31
|
+
crawlLinks: true,
|
|
32
|
+
autoStaticPathsDiscovery: false,
|
|
33
|
+
},
|
|
23
34
|
sitemap: config.site
|
|
24
35
|
? { enabled: true, host: config.site }
|
|
25
36
|
: { enabled: false },
|
|
26
|
-
router: {
|
|
37
|
+
router: {
|
|
38
|
+
generatedRouteTree: "routeTree.gen.ts",
|
|
39
|
+
basepath: config.base,
|
|
40
|
+
},
|
|
27
41
|
}),
|
|
28
42
|
react(),
|
|
29
43
|
svgr(),
|