docs/content/content/links.md (2636B)
1 +++
2 title = "Internal links"
3 description = "Links that point at the source file, and URLs the build writes"
4 weight = 20
5 toc = true
6 +++
7
8 Write a link to the *file* and sqzass turns it into that page's URL:
9
10 ```markdown
11 See [Installation](@/start/installation.md).
12 ```
13
14 The path after `@/` is relative to `content/`, and it points at the markdown
15 file, not the URL. Move the file, rename it, or change its `slug`, and the link
16 follows.
17
18 ## Broken links stop the build
19
20 An `@/` link that resolves to nothing is an error:
21
22 ```
23 docs/content/start/first-site.md: 어디도 가리키지 않는 링크가 있습니다:
24 @/start/setup.md
25 ```
26
27 This is the point of the syntax. A plain `/start/setup/` link that goes nowhere
28 is indistinguishable from one that works until somebody clicks it in
29 production. A reference the build can check is a reference the build *does*
30 check.
31
32 ## They follow the reader's language
33
34 `@/start/installation.md` resolves to `/start/installation/` for an English
35 reader and `/ko/start/installation/` for a Korean one — the same markdown, in
36 both language trees, without a single conditional.
37
38 If the target has no translation in the current language, the link falls back
39 to the default language rather than breaking. See
40 [Languages](@/content/languages.md).
41
42 Because of that fallback, you write the path once and never write it with a
43 language prefix. `@/ko/start/installation.md` is not a thing.
44
45 ## It happens on the tree
46
47 Rewriting is done through comrak's URL rewriter, on the AST, before any HTML
48 exists. The shortcut — running a regex over the finished HTML — silently skips
49 any element whose attributes are single-quoted or unquoted, which produces a
50 class of bug you find in production rather than in the build.
51
52 Images go through the same *checker*, but not the same syntax. `@/` resolves
53 against the table of markdown pages, and an image in `static/` is not in it, so
54 `` stops the build. Write the root-absolute path instead —
55 `` — and the build verifies the file is there, so a typo in an
56 image path fails the same way a typo in a link does.
57
58 ## Generated files are link targets too
59
60 `/sitemap.xml`, `/robots.txt`, `/llms.txt`, `/404.html`, `/feed-<lang>.xml` and
61 `/search-<lang>.json` are pages as far as the checker is concerned — the build
62 produces them, so a link to one resolves.
63
64 The exception is anything content-hashed. `/css/main.css` does not exist after a
65 build; `asset("css/main.css")` in a template is the way to reach it.
66
67 ## Everything else is left alone
68
69 External links, anchors, `mailto:` — untouched. sqzass only claims the `@/`
70 prefix.