@evertondgn/solid-tooling 0.4.0 → 0.6.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.
Files changed (43) hide show
  1. package/README.md +193 -578
  2. package/app-env.d.ts +7 -0
  3. package/dist/architecture-plugin.mjs +1 -1
  4. package/dist/backend-plugin.mjs +139 -4
  5. package/dist/cli.d.mts +1 -0
  6. package/dist/cli.mjs +42 -0
  7. package/dist/commitlint.d.mts +3 -0
  8. package/dist/commitlint.mjs +28 -0
  9. package/dist/{constants-Jqvtbvxu.mjs → constants-BZJm7ouk.mjs} +1 -1
  10. package/dist/css-filename-CEHQd2gz.mjs +40 -0
  11. package/dist/css-filename.mjs +1 -40
  12. package/dist/fmt-9dlUYOMk.mjs +34 -0
  13. package/dist/fmt.mjs +1 -34
  14. package/dist/i18n-generate.d.mts +1 -0
  15. package/dist/i18n-generate.mjs +23 -0
  16. package/dist/i18nPlugin-CS7Gob6R.mjs +109 -0
  17. package/dist/knip.d.mts +2 -1
  18. package/dist/knip.mjs +7 -2
  19. package/dist/{lint-UTfyg7AR.mjs → lint-ehdtTKfw.mjs} +33 -86
  20. package/dist/lint.mjs +1 -1
  21. package/dist/playwright-teardown.mjs +1 -1
  22. package/dist/playwright.d.mts +2 -1
  23. package/dist/playwright.mjs +4 -3
  24. package/dist/prepareMessages-BXmY6Ko2.mjs +222 -0
  25. package/dist/project-plugin.mjs +2 -2
  26. package/dist/protocol-DSNNUYja.mjs +18 -0
  27. package/dist/publication/read-llms-index.d.mts +12 -0
  28. package/dist/publication/read-llms-index.mjs +1 -0
  29. package/dist/publication-CRUTOB0B.mjs +885 -0
  30. package/dist/readLlmsIndex-Gj4iTxAk.mjs +27 -0
  31. package/dist/stylelint.mjs +2 -2
  32. package/dist/test-locale--tuH0Np5.mjs +3 -0
  33. package/dist/types-DHu2Z_ot.d.mts +49 -0
  34. package/dist/vite.d.mts +33 -7
  35. package/dist/vite.mjs +415 -88
  36. package/dist/vitest-BjLr7iLf.mjs +362 -0
  37. package/dist/vitest.d.mts +3 -7
  38. package/dist/vitest.mjs +1 -129
  39. package/lefthook.yml +57 -0
  40. package/node-env.d.ts +1 -0
  41. package/package.json +54 -35
  42. package/tsconfig.app.json +4 -9
  43. package/virtual-modules.d.ts +90 -0
package/README.md CHANGED
@@ -1,71 +1,50 @@
1
- # @evertondgn/solid-tooling
2
-
3
- Lint preset, formatter config, TypeScript configs, test configs, the Knip and
4
- Stylelint configs and the Vite+ application config for SolidJS 2 applications
5
- built with [Vite+](https://viteplus.dev/guide/).
6
-
7
- The package contains the lint, format, TypeScript, test, build, dead code and
8
- CSS lint setup of
9
- [boilerplate_solidjs](https://github.com/everton-dgn/boilerplate_solidjs), a
10
- SolidJS application template. Applications created from it install the package
11
- instead of copying the files, so a rule change reaches them through a version
12
- update.
13
-
14
- ## Requirements
15
-
16
- The application installs three packages next to this one:
1
+ [![Latest solid-tooling version on npm](https://img.shields.io/npm/v/@evertondgn/solid-tooling)](https://www.npmjs.com/package/@evertondgn/solid-tooling)
2
+ [![CI workflow status](https://github.com/everton-dgn/solidjs_base/actions/workflows/ci.yml/badge.svg)](https://github.com/everton-dgn/solidjs_base/actions/workflows/ci.yml)
3
+ [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/everton-dgn/solidjs_base/blob/main/LICENSE)
17
4
 
18
- | Package | Why |
19
- | ---------------------- | ----------------------------------------------------------- |
20
- | `vite-plus` | Runs lint and format, and provides the Oxlint plugin API |
21
- | `@inlang/paraglide-js` | The preset registers its lint plugin, resolved from the app |
22
- | `typescript` | The preset turns on type-aware linting and type checking |
23
-
24
- `vite-plus` and `@inlang/paraglide-js` are peer dependencies, pinned to the
25
- exact versions the package is tested with. Install the versions listed in its
26
- `peerDependencies`. `typescript` is not a peer dependency: the package is tested
27
- with the version in its `devDependencies`.
28
-
29
- `eslint-plugin-solid`, `stylelint` and `stylelint-use-nesting` come with the
30
- package, so the application does not declare them.
31
-
32
- Some entries need tools the application already runs:
33
-
34
- | Entry | The application installs |
35
- | -------------- | ------------------------------------------------------------------------------- |
36
- | `./vitest` | `@vitest/browser-playwright`, `@vitest/coverage-v8`, `happy-dom`, `playwright` |
37
- | `./playwright` | `@playwright/test`, an optional peer dependency pinned like the others |
38
- | `./knip` | `knip` and `filesystem-routing`, optional peer dependencies pinned the same way |
5
+ # @evertondgn/solid-tooling
39
6
 
40
- `./vite` also needs the test tools of `./vitest`, and loads four plugin
41
- packages: `@solidjs/vite-plugin`, `nitro`, `filesystem-routing` and
42
- `unplugin-icons`. They are optional peer dependencies pinned like the others.
43
- Install the versions listed in `peerDependencies` as direct dependencies of the
44
- application: Bun applies `overrides` and `patchedDependencies` only from the
45
- root `package.json`, and the Knip plugin of `unplugin-icons` only turns on with
46
- a direct dependency.
7
+ <picture>
8
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/hero-dark.webp" />
9
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/hero-light.webp" />
10
+ <img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/hero-light.webp" alt="Solid Base for SolidJS 2 and Vite+. Shared tooling and runtime beneath the SolidJS mark: languages, theme, server protection, SEO, assets and development tools. Install solid-tooling for development and solid-runtime for application features." width="800" />
11
+ </picture>
47
12
 
48
- ## Install
13
+ | Available package | Role |
14
+ | ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
15
+ | [`@evertondgn/solid-tooling`](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-tooling/README.md) | Shared config, tools, catalog generation, icons and fonts |
16
+ | [`@evertondgn/solid-runtime`](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-runtime/README.md), `0.1.0` | Optional locale and theme behavior, middleware, error protection, env, SEO and sitemap |
49
17
 
50
- `vp` is the Vite+ CLI. An application built with Vite+ already has `vite-plus`
51
- and `typescript`, so it only adds this package:
18
+ Solid Base supplies lint rules, application config, test setups and Git hooks
19
+ for SolidJS 2 with [Vite+](https://viteplus.dev/guide/) as one versioned
20
+ dependency, so you stop maintaining the same tooling in every Solid app. In an
21
+ application that already uses Vite+:
52
22
 
53
23
  ```bash
54
24
  vp add -D @evertondgn/solid-tooling
55
25
  ```
56
26
 
57
- An application without `@inlang/paraglide-js` adds it too, in the version the
58
- package asks for:
27
+ Built for applications that follow the
28
+ [boilerplate_solidjs](https://github.com/everton-dgn/boilerplate_solidjs)
29
+ layout. SolidJS 2 is still a release candidate, and the package is tested with
30
+ it. Start with lint and formatting, and adopt the full application config when
31
+ you are ready.
59
32
 
60
- ```bash
61
- npm view @evertondgn/solid-tooling peerDependencies
62
- vp add -D @inlang/paraglide-js@<version>
63
- ```
33
+ ## Requirements
34
+
35
+ Install the exact Vite+ version listed in the package's `peerDependencies`. The
36
+ package supplies its build, test, type-check and hook tools. Applications keep
37
+ their own direct imports and the Vite+ overrides; see the
38
+ [dependency requirements](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/limits.md#requirements).
39
+ An application with translations also installs the required version of
40
+ `@inlang/paraglide-js` and its message-format plugin.
64
41
 
65
- ## Usage
42
+ ## Quick start
43
+
44
+ Add `fmt` and `lint` to your existing Vite+ config. The example shows only those
45
+ settings; keep your plugins and other options:
66
46
 
67
47
  ```ts
68
- // vite.config.ts
69
48
  import { fmt } from '@evertondgn/solid-tooling/fmt'
70
49
  import { lint } from '@evertondgn/solid-tooling/lint'
71
50
  import { defineConfig } from 'vite-plus'
@@ -73,8 +52,9 @@ import { defineConfig } from 'vite-plus'
73
52
  export default defineConfig({ fmt, lint })
74
53
  ```
75
54
 
55
+ In `tsconfig.json`:
56
+
76
57
  ```json
77
- // tsconfig.json
78
58
  {
79
59
  "extends": "@evertondgn/solid-tooling/tsconfig.base.json",
80
60
  "compilerOptions": {
@@ -84,83 +64,70 @@ export default defineConfig({ fmt, lint })
84
64
  }
85
65
  ```
86
66
 
87
- `vp check`, `vp lint` and `vp fmt` read both configs from `vite.config.ts`.
88
-
89
- ## Tests
67
+ Check your code and format your files:
90
68
 
91
- `solidTest` returns the `test` block of `vite.config.ts`, with three Vitest
92
- projects:
93
-
94
- | Project | Files | Environment |
95
- | --------- | -------------------------------- | ------------------------------------------------ |
96
- | `node` | `src/**/*.node.test.{ts,tsx}` | Node, with stand-ins for the build-only modules |
97
- | `dom` | `src/**/*.dom.test.{ts,tsx}` | happy-dom at `http://localhost/en` |
98
- | `browser` | `src/**/*.browser.test.{ts,tsx}` | Chromium through Playwright, with the CSS loaded |
69
+ ```bash
70
+ vp check
71
+ vp fmt
72
+ ```
99
73
 
100
- `defineSolidApp` from `./vite` already calls `solidTest`. An application that
101
- builds its own Vite config calls it directly:
74
+ To see a rule of the package fire, create `src/helpers/export-list.ts`:
102
75
 
103
76
  ```ts
104
- // vite.config.ts
105
- import { solidTest } from '@evertondgn/solid-tooling/vitest'
106
- import solid from '@solidjs/vite-plugin'
107
- import { defineConfig } from 'vite-plus'
77
+ const example = 1
108
78
 
109
- export default defineConfig({
110
- test: solidTest({
111
- root: import.meta.dirname,
112
- plugins: () => [solid({ serverFunctions: true })]
113
- })
114
- })
79
+ export { example }
115
80
  ```
116
81
 
117
- `plugins` is a function that returns the Vite plugins the `dom` and `browser`
118
- projects need to compile components: Solid, routes, icons and i18n. The preset
119
- calls it once per project, because each project starts its own Vite server and a
120
- plugin instance keeps the state of one server. The preset also sets the coverage
121
- thresholds, the reporters and the workers on CI, passes `BASE_URL_TEST`, `HOST`
122
- and `PORT` to the tests when they are set, and resets the Paraglide locale
123
- before each browser test.
82
+ Run `vp lint`. The preset reports the export list:
124
83
 
125
- The `node` project does not load the Solid and routing plugins, so a plugin of
126
- the preset serves `server-only`, `virtual:file-routes` and
127
- `virtual:solid-server-function-handler`. Knip does not know `server-only`, a
128
- virtual module of `@solidjs/vite-plugin`: pass it in the `ignoreDependencies` of
129
- [`defineKnipConfig`](#knip).
84
+ ```text
85
+ src/helpers/export-list.ts:3:1: error project(no-export-list): Export on the declaration itself (export function, export const, export type) instead of using export { ... }. An export list is only allowed in a re-export with from.
86
+ ```
130
87
 
131
- `definePlaywrightConfig` builds the Playwright config from the application root:
88
+ ## Why
132
89
 
133
- ```ts
134
- // playwright.config.ts
135
- import { definePlaywrightConfig } from '@evertondgn/solid-tooling/playwright'
90
+ Applications copied from a starter carry its tooling with them, and every fix to
91
+ the base has to be repeated by hand in each copy. With this package, the fix
92
+ arrives when you update a dependency.
136
93
 
137
- export default definePlaywrightConfig({ root: import.meta.dirname })
138
- ```
94
+ <picture>
95
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/before-after-dark.webp" />
96
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/before-after-light.webp" />
97
+ <img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/before-after-light.webp" alt="About 86 percent fewer lines across five configuration areas, from 945 to 136: Vite 427 to 59, Playwright 173 to 17, Knip 129 to 40, TypeScript 45 to 9, and Stylelint 171 to an 11-line script. Each bar shows the fraction retained in the app." width="800" />
98
+ </picture>
139
99
 
140
- It reads `BASE_URL_TEST` from `.env.test`, builds the application (`e2e` mode
141
- for the fixture routes, `production` with `TEST_PRODUCTION_ROUTES=true`), starts
142
- the preview, and checks the server log for private markers when the suite ends.
143
- `TEST_PREBUILT=true` reuses an existing production build.
100
+ Measured on the original starter and the same application using this package.
101
+ Compare the
102
+ [original config](https://github.com/everton-dgn/boilerplate_solidjs/blob/61454937472d0faa1b4fab985fd7c5da968aa9a6/vite.config.ts)
103
+ with the
104
+ [application config](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/vite.config.ts),
105
+ or read the
106
+ [full comparison](https://github.com/everton-dgn/solidjs_base/blob/main/README.md#before-and-after).
144
107
 
145
- | Option | Default | Use |
146
- | ---------------- | ----------------- | ---------------------------------------------------------------------- |
147
- | `testDir` | `src/tests/pages` | Folder of the `*.e2e.test.ts` files |
148
- | `fixtureServers` | none | Extra servers for the fixture routes, as `{ command, url }` |
149
- | `suites` | none | Globs of serial suites: `serverLogs`, `markdown` and `publicationLoad` |
108
+ ## What you get
150
109
 
151
- Each serial suite gets its own project: `markdown` runs with one worker,
152
- `serverLogs` runs last as the teardown of the others, and `publicationLoad` runs
153
- alone, against two servers, with `TEST_PUBLICATION_LOAD=true`.
110
+ | Area | Entry | Guide |
111
+ | ------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
112
+ | Oxlint preset and project rules | `./lint` | [Lint](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/lint.md) |
113
+ | Oxfmt settings | `./fmt` | [Formatting](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/typescript-and-format.md#formatter) |
114
+ | TypeScript configs | `./tsconfig.base.json`, `./tsconfig.app.json` | [TypeScript](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/typescript-and-format.md#typescript-base) |
115
+ | Whole application config | `./vite` | [Application config](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/app-config.md) |
116
+ | Vitest and Playwright | `./vitest`, `./playwright` | [Testing](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/testing.md) |
117
+ | Unused code and CSS policy | `./knip`, `./stylelint` | [Knip and CSS](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/knip-and-css.md) |
118
+ | Commit messages and Git hooks | `./commitlint`, `./lefthook.yml` | [Commits and hooks](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/commits-and-hooks.md) |
154
119
 
155
- ## Application config
120
+ Your application keeps its pages, components, translations, theme, `App`,
121
+ `Document`, entries and middleware. The
122
+ [entry-point reference](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/README.md#entry-points)
123
+ also lists the plugins and test setup exports.
156
124
 
157
- `defineSolidApp` returns the whole `vite.config.ts` of a boilerplate
158
- application: the Solid, routing, icons and Nitro plugins, the headers of the
159
- static files, the build, CSS, server and preview blocks, the `vp run` tasks, and
160
- `lint`, `fmt` and `test` from the presets above.
125
+ ## Your application config in one call
126
+
127
+ With the application dependencies installed, `defineSolidApp()` supplies the
128
+ plugins, build settings, tasks, lint, format and three Vitest projects:
161
129
 
162
130
  ```ts
163
- // vite.config.ts
164
131
  import { defineSolidApp } from '@evertondgn/solid-tooling/vite'
165
132
 
166
133
  import { SECURITY_HEADERS } from './src/middleware/securityHeaders/constants.ts'
@@ -168,477 +135,125 @@ import { SECURITY_HEADERS } from './src/middleware/securityHeaders/constants.ts'
168
135
  export default defineSolidApp({
169
136
  root: import.meta.dirname,
170
137
  middleware: './src/middleware/index.ts',
171
- securityHeaders: SECURITY_HEADERS,
172
- staticPaths: ['/favicon/**']
173
- })
174
- ```
175
-
176
- | Option | Default | Use |
177
- | ----------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
178
- | `root` | required | Application folder. `.env`, `.env.test`, `project.inlang/settings.json` and the icon folders resolve from it |
179
- | `securityHeaders` | required | Values of `strict-transport-security`, `x-content-type-options` and `cross-origin-resource-policy` for the static files |
180
- | `middleware` | none | `start.middleware` of the Solid plugin. It has to sit inside the application folder |
181
- | `serverSetup` | `serverFunctions: true` | `serverFunctions.serverSetup` of the Solid plugin |
182
- | `e2e` | production paths | `{ middleware, routes }` for `--mode e2e`: the middleware chain and the route folder of the fixtures, without route types |
183
- | `icons` | none | Own `unplugin-icons` collections, as name to folder |
184
- | `publicAssets` | none | `publicAssets` of Nitro. Each entry needs a `baseURL`, which also gets the static headers |
185
- | `staticPaths` | none | Other static paths that get the headers, such as `/favicon/**` |
186
- | `routeRules` | none | More Nitro route rules, applied after the static ones. A rule with the same path replaces the static one |
187
- | `extend` | none | `(context) => ({ plugins, nitroModules })`, for plugins and Nitro modules the application still owns |
188
- | `tasks` | none | Adds or replaces `vp run` tasks by name |
189
- | `workspace` | none | `{ dependsOn, inputs }` for an application inside a monorepo, whose `bun.lock`, `bunfig.toml` and package builds sit at the root |
190
-
191
- The preset fixes the rest:
192
-
193
- - Plugins, in this order: the `extend` plugins, `unplugin-icons` (Solid
194
- compiler, `aria-hidden` on every icon), `@solidjs/vite-plugin` with SSR and
195
- server functions, `filesystem-routing` with HTTP methods and the route types
196
- in `src/@types/routes.d.ts`, and Nitro with the `vercel` preset. The `dom` and
197
- `browser` test projects get the `extend` plugins, the icons, Solid with server
198
- functions only and the routes. The `test` mode loads no application plugin and
199
- reads `.env.test` into `process.env`.
200
- - The static headers go to `/assets/**`, each `publicAssets` folder, the
201
- `staticPaths`, `/<locale>/**.md` for each locale of
202
- `project.inlang/settings.json`, `/llms.txt`, `/llms-full.txt`, `/sitemap.xml`,
203
- `/sitemaps/pages/**` and `/_markdown/static.json`. The static files leave the
204
- CDN without going through the middleware, so these rules give them the headers
205
- the middleware writes on the other responses.
206
- - `build.manifest` only in the `e2e` mode, which the `TEST_PREBUILT` check of
207
- `./playwright` relies on, and no comments in the output.
208
- - Lightning CSS, with CSS Modules classes named `[content-hash]_[local]`.
209
- - `resolve.tsconfigPaths`, and the dev server and the preview on the `HOST` and
210
- `PORT` of `.env`. The dev server forwards the browser console to the terminal.
211
-
212
- The plugins are imported inside `lazyPlugins`, so `vp lint`, `vp fmt` and
213
- `vp check` read the config without loading them.
214
-
215
- Nitro compiles the route rules with the `preMerge` of h3, which refuses rules
216
- that overlap in part, such as `/pt/blog/**` next to `/pt/**.md`, and falls back
217
- to its simple mode, with the same result and a warning. `defineSolidApp` throws
218
- when a `publicAssets` entry has no `baseURL`, or one with a trailing slash, and
219
- when a static path does not start with `/`. Build, dev and preview fail to load
220
- the plugins when a `publicAssets` folder or a static path sits inside a locale
221
- folder.
222
-
223
- ### `extend`
224
-
225
- `extend` runs inside `lazyPlugins`: once for the application in build, dev and
226
- preview (`target: 'app'`), and once for each test project with a Vite server
227
- (`target: 'test'`). Every load of the config calls it again, so a build also
228
- calls it for the two test projects, whose plugins Vite does not use; keep side
229
- effects out of it. It never runs while Vite+ only reads the config. Return new
230
- plugin instances on each call. The `plugins` go before the fixed ones, and the
231
- `nitroModules` go to Nitro; the `test` target ignores them. One call returns
232
- both, so a value that a plugin and a module share, such as a build id, stays the
233
- same.
234
-
235
- ```ts
236
- export default defineSolidApp({
237
- root: import.meta.dirname,
238
- securityHeaders: SECURITY_HEADERS,
239
- async extend() {
240
- const { i18nPlugin } = await import('./tooling/i18n/i18nPlugin/index.ts')
241
- return { plugins: [i18nPlugin()] }
242
- }
138
+ securityHeaders: SECURITY_HEADERS
243
139
  })
244
140
  ```
245
141
 
246
- ### Tasks
247
-
248
- | Task | Command |
249
- | ------------------- | ------------------------------------------------------------------------------------------------------- |
250
- | `i18n-generate` | `bun tooling/i18n/generate.ts` |
251
- | `lint-css` | `bun tooling/css/check.ts` |
252
- | `dead-code-project` | `knip-bun --config tooling/knip.ts`, then again with `--strict` |
253
- | `lint-project` | `vp lint`, after `lint-css` |
254
- | `check-project` | `vp fmt --check && vp lint`, after `lint-css` |
255
- | `typecheck-node` | `tsc --project tsconfig.node.json` |
256
- | `test-tooling` | `node --test` over `tooling/**/__tests__` except `tooling/release/`, three workers on CI, with no cache |
257
-
258
- The commands run the scripts of the boilerplate layout. An application without
259
- one of them replaces the task through `tasks`. Knip reads task commands only
260
- from a `run.tasks` block written in `vite.config.ts`, so it does not see these:
261
- list the scripts they run as Knip entries.
262
-
263
- With `workspace`, the cache inputs read `bun.lock`, `bunfig.toml` and the
264
- `inputs` from the workspace root, and `lint-css`, `dead-code-project` and
265
- `typecheck-node` depend on the tasks in `dependsOn`:
142
+ You keep your middleware and header values. SSR uses Nitro with the Vercel
143
+ preset. Its plugins are package dependencies pinned to the tested versions. The
144
+ `knip`, `tsc`, `playwright`, `lefthook` and `commitlint` tasks run the
145
+ package-owned binaries, including with an isolated installation.
146
+
147
+ | Feature | Selection |
148
+ | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
149
+ | Client-only build | Set `ssr: false` and omit SSR options such as `middleware` and `securityHeaders`; the build has no Nitro or server bundle |
150
+ | Publication headers | Set `seo.markdown`, `seo.llms`, `seo.llmsFull` and `seo.sitemap` independently; static artifacts come from compiled tooling |
151
+ | Translations | `project.inlang/settings.json` enables the generation task and browser test setup; the lint plugin loads only where Paraglide resolves |
152
+
153
+ See
154
+ [all options and extension points](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/app-config.md)
155
+ and the
156
+ [known limits](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/limits.md#known-limits).
157
+
158
+ ## Optional application fonts
159
+
160
+ Pass a data-only `fonts` array to `defineSolidApp` to generate external
161
+ `@font-face` CSS and matching preloads for application-owned files. SSR uses
162
+ `FontLinks` from `@evertondgn/solid-runtime/fonts/font-links` in the Document
163
+ head; client-only applications receive both links in `index.html`. Without
164
+ `fonts`, nothing is generated. Typography tokens stay in the app. See the
165
+ [font API and migration examples](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/fonts.md).
166
+
167
+ ## Optional SEO configuration
168
+
169
+ For SSR,
170
+ `seo: { robots: { groups, sitemapPaths, cacheControl }, sitemap: true }`
171
+ configures the runtime robots route using serializable data. `originEnv`
172
+ defaults to `VITE_SITE_URL`; the value must be an HTTP(S) origin without a path,
173
+ query, fragment or credentials. The preset validates it when SEO is enabled or
174
+ the runtime origin entry is imported. No SEO means no required origin.
175
+
176
+ Pass `site` directly to the runtime `createSeo` primitive. A meta/JSON-LD-only
177
+ application can omit `seo`, provide its own `site.url` and omit robots entirely.
178
+ Client-only applications omit both the option and runtime SEO imports. There are
179
+ no `siteModule`, `sourcesModule` or `editorialModule` path options.
180
+ `seo.sitemap` controls only the static `/sitemap.xml` and `/sitemaps/pages/**`
181
+ header rules. Install the runtime factory in explicit application route files,
182
+ and list the root in `robots.sitemapPaths` to advertise it. To remove sitemap,
183
+ remove its routes and server binding, omit its array metadata, omit
184
+ `sitemapPaths`, and omit or disable `seo.sitemap`. Robots can stay enabled. The
185
+ preset does not discover executable source registries or install routes. See the
186
+ [runtime SEO API](../solid-runtime/README.md#optional-seo) for factories, the
187
+ one-line route and examples with and without translations.
188
+
189
+ ## Optional environment validation
190
+
191
+ An SSR application can add `env.ts` with the preset's optional validators:
266
192
 
267
193
  ```ts
268
- workspace: {
269
- dependsOn: ['@evertondgn/solid-tooling#build'],
270
- inputs: ['packages/solid-tooling/dist/**']
271
- }
272
- ```
273
-
274
- ### Changing the result
194
+ import { serverEnv } from '@evertondgn/solid-runtime/env'
275
195
 
276
- Wrap the result in `defineConfig` and merge what the application needs. Vite+
277
- removes the plugins it injected before it injects them again, so they are not
278
- duplicated:
196
+ const env = { server: { ...serverEnv } }
279
197
 
280
- ```ts
281
- import { defineSolidApp } from '@evertondgn/solid-tooling/vite'
282
- import { defineConfig, mergeConfig } from 'vite-plus'
283
-
284
- const app = defineSolidApp({ root: import.meta.dirname, securityHeaders })
285
-
286
- export default defineConfig(env =>
287
- mergeConfig(app(env), { server: { strictPort: true } })
288
- )
198
+ export default env
289
199
  ```
290
200
 
291
- ## Knip
292
-
293
- `defineKnipConfig` returns the Knip config of the application as a function, the
294
- form Knip accepts as the default export of its config file:
295
-
296
- ```ts
297
- // tooling/knip.ts
298
- import path from 'node:path'
299
-
300
- import { defineKnipConfig } from '@evertondgn/solid-tooling/knip'
301
-
302
- export default defineKnipConfig({
303
- root: path.resolve(import.meta.dirname, '..'),
304
- ignoreDependencies: ['server-only']
305
- })
306
- ```
307
-
308
- Run it with `knip-bun --config tooling/knip.ts`, then with `--strict`. The
309
- config lists:
310
-
311
- - `src/entry-server.tsx`, `src/entry-client.tsx`, `src/middleware/index.ts`,
312
- `env.ts` and `paraglide/runtime.js` as production entries. The Solid plugin
313
- and the Paraglide runtime load them by path, and Knip does not read the Solid
314
- plugin when `vite.config.ts` imports it with `import()`, as `./vite` does. An
315
- application that imports `solid()` statically, with `start`, passes
316
- `solidPluginImport: 'static'`: Knip's Solid plugin then finds the first four
317
- itself, and listing them again would be a configuration hint.
318
- - Every page and HTTP handler that `filesystem-routing` finds in `src/routes/`,
319
- as production entries, and in `src/tests/fixtures/routes/` and
320
- `src/tests/fixtures/e2e/routes/`, as test entries. The `filesystem-routing`
321
- plugin of Knip is turned off, because it takes every file of `src/routes/` as
322
- an entry and would hide unused helpers next to the routes.
323
- - `src/**/*.{ts,tsx}` and `tooling/**/*.ts` as the project, with the tests out
324
- of the production files.
325
-
326
- The config turns on `treatConfigHintsAsErrors`, and Knip reports an entry or a
327
- project pattern without files as a configuration hint. So each default above
328
- enters only when the application has the file or the folder.
329
-
330
- | Option | Default | Use |
331
- | -------------------- | ----------------- | -------------------------------------------------------------- |
332
- | `root` | required | The application folder |
333
- | `configFile` | `tooling/knip.ts` | Path of the config file, relative to `root` |
334
- | `entry` | none | More entries, such as a public API that only test fixtures use |
335
- | `solidPluginImport` | `'lazy'` | `'static'` when `vite.config.ts` imports `solid()` statically |
336
- | `ignoreBinaries` | none | Passed to Knip as is |
337
- | `ignoreDependencies` | none | Passed to Knip as is |
338
- | `ignoreIssues` | none | Passed to Knip, merged with the entry for `configFile` |
339
- | `exclude` | none | Issue types to leave out, such as `catalogReferences` |
340
-
341
- Knip adds the file given to `--config` to the entries in production mode, and
342
- `--strict` only accepts `dependencies` there, so it reports this package as an
343
- unlisted dependency of the config file. The config ignores `unlisted` issues in
344
- `configFile` only: an import of this package from `src/` is still reported. An
345
- application that keeps the config somewhere else passes its path in
346
- `configFile`.
347
-
348
- Nothing that depends on the application is a default. An ignore that matches
349
- nothing is a configuration hint too, so `server-only` and the binaries of the
350
- scripts are options. For a key without an option, wrap the function:
351
-
352
- ```ts
353
- const configure = defineKnipConfig({ root })
354
-
355
- export default async function configureKnip() {
356
- return { ...(await configure()), ignoreUnresolved: ['virtual:example'] }
357
- }
358
- ```
359
-
360
- ## CSS lint
361
-
362
- `checkCss(root)` lints `src/**/*.css` with Stylelint and the CSS policy of the
363
- boilerplate, and checks the name of every CSS file in `src/` as
364
- `project/css-filename` does for imports: `styles.module.css`, or `camelCase.css`
365
- inside `src/theme/`. It returns the report and whether anything failed:
366
-
367
- ```ts
368
- // tooling/css/check.ts
369
- import path from 'node:path'
370
- import process from 'node:process'
371
-
372
- import { checkCss } from '@evertondgn/solid-tooling/stylelint'
373
-
374
- const { report, hasErrors } = await checkCss(
375
- path.resolve(import.meta.dirname, '../..')
376
- )
377
-
378
- process.stdout.write(report)
379
- if (hasErrors) process.exitCode = 1
380
- ```
381
-
382
- `defineStylelintConfig(root)` returns the Stylelint config that `checkCss` uses.
383
- The policy:
384
-
385
- - Classes use snake_case, nesting goes at most two levels deep, and adjacent
386
- state selectors and media queries are nested (`stylelint-use-nesting`).
387
- - Unknown or invalid properties, values, units, selectors, at-rules and media
388
- features are errors, as are deprecated and unmatchable selectors.
389
- - Outside `src/theme/`, colors, gradients, radii, shadows, font sizes and
390
- weights and `z-index` come from tokens with `var()`, from the matching token
391
- family. Literal colors, color functions and system colors are errors.
392
- - Inside `src/theme/`, the token rules are off, so the theme can define the
393
- values with `oklch()`, `oklab()`, `color-mix()`, `light-dark()` and system
394
- colors. Hex, named colors and the `rgb()`, `hsl()`, `hwb()`, `lab()`, `lch()`
395
- and `color()` functions are still errors there.
396
- - `var()` and animation names resolve against `src/theme/tokens/**/*.css` and
397
- `src/theme/class/animation.css`. Stylelint stops the whole run when a
398
- reference matches no file, so each one is passed only when it exists.
399
- - An exception needs a `stylelint-disable` comment with the reason after `--`.
400
-
401
- `stylelint` and `stylelint-use-nesting` are dependencies of this package. The
402
- config passes the plugin by a path resolved from the package, because Stylelint
403
- looks up a plugin name from the application and its working directory, where it
404
- is not installed.
405
-
406
- ## Project layout the preset expects
407
-
408
- The rules match file paths relative to the folder where lint runs, so run it
409
- from the application root. They know these locations:
410
-
411
- | Path | Meaning |
412
- | --------------------------------------------- | -------------------------------------------------------- |
413
- | `src/` | Application code. The `@/` alias points here |
414
- | `src/routes/` | Pages. Each page may have a `seo.ts` module |
415
- | `src/components/{atoms,molecules,organisms}/` | UI layers |
416
- | `src/primitives/` | Shared primitives |
417
- | `src/infra/server/` | Backend adapters and server error handling |
418
- | `src/theme/` | Global CSS |
419
- | `src/tests/pages/<Page>/` | End-to-end tests, one folder per page |
420
- | `paraglide/` | Generated i18n modules. The `@paraglide/` alias |
421
- | `tooling/` | Project scripts and their tests, written for `node:test` |
422
-
423
- An application with another layout can still use the preset, but it has to
424
- override the rules that do not fit. See
425
- [Changing the preset](#changing-the-preset).
426
-
427
- ## What the lint preset turns on
428
-
429
- - Oxlint plugins: `import`, `jsx-a11y`, `node`, `oxc`, `promise`, `typescript`,
430
- `unicorn` and `vitest`.
431
- - JavaScript plugins: `solid`, `paraglide`, `vite-plus` and the three plugins of
432
- this package (`project`, `backend`, `architecture`).
433
- - Type-aware rules and type checking (`typeAware`, `typeCheck`).
434
- - Warnings fail the run (`denyWarnings`), and an unused disable directive is an
435
- error.
436
-
437
- Every rule is listed by name in the preset. No Oxlint category is enabled, so an
438
- Oxlint update does not add rules on its own.
439
-
440
- ### Rules of this package
441
-
442
- | Rule | What it enforces |
443
- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
444
- | `project/css-modules-import` | A CSS Module is imported as the default binding `S` |
445
- | `project/css-filename` | A CSS file imported from `src/` is named `styles.module.css`, or `camelCase.css` inside `src/theme/` |
446
- | `project/test-filename` | A test file sits in `__tests__` next to its module and is named after it, plus the environment: `Button/__tests__/Button.dom.test.tsx` |
447
- | `project/no-export-list` | Exports sit on the declaration. `export { a, b }` is only allowed with `from` |
448
- | `project/seo-module` | A route `seo.ts` exports only `seo`. It has no relative value import, no value import from `src/routes/`, no computed `import()` and no `import.meta.glob` |
449
- | `backend/static-solid-imports` | No `import()` of `@solidjs/web` or its subpaths |
450
- | `backend/static-render-integrity-imports` | No `import()` of the `renderIntegrity` module |
451
- | `architecture/layer-imports` | Lower layers do not import upper ones, and production code does not import tests or `tooling/` |
452
-
453
- These rules read import specifiers as text. They resolve relative paths and the
454
- `@/`, `@paraglide/` and `/src/` prefixes. An `import()` with a computed path and
455
- any other alias are not checked, except in `seo.ts`, where a computed `import()`
456
- is an error.
457
-
458
- `architecture/layer-imports` checks these directions:
459
-
460
- - The base layer (`src/@types`, `constants`, `helpers`, `data`, `infra`,
461
- `theme`, `i18n` and `paraglide/`) does not import primitives, components,
462
- routes or entry files.
463
- - `src/primitives` does not import components, routes or entry files.
464
- - Atoms do not import molecules or organisms, and molecules do not import
465
- organisms.
466
- - No production file imports a test or `tooling/`.
467
-
468
- The entry files are `App`, `Document`, `entry-server`, `entry-client`, `router`
469
- and `middleware`, at the root of `src/`.
470
-
471
- `project/test-filename` accepts these names:
472
-
473
- - `Name.<environment>.test.ts(x)` in `src/`, where the environment is `node`,
474
- `dom`, `browser` or `e2e`.
475
- - `Name.test-d.ts(x)` in `src/`, for type tests.
476
- - `Name.test.ts` in `tooling/`.
477
-
478
- `Name` is the folder that holds `__tests__`. A qualifier may follow it:
479
- `Button.focus.dom.test.tsx`. End-to-end tests are the exception: they live in
480
- `src/tests/pages/<Page>/` and are named after the page.
481
-
482
- ### Backend restrictions
483
-
484
- Inside `src/`, the preset also restricts what code can reach:
485
-
486
- - `console` is not allowed. `src/infra/server/logServerFailure/index.ts` is the
487
- only module that may call `console.error`.
488
- - `fetch`, `XMLHttpRequest`, `WebSocket` and `EventSource` are not allowed.
489
- `src/infra/server/requestJson/index.ts` is the only module that may call
490
- `fetch`.
491
- - The Node transports (`http`, `https`, `http2`, `net`, `tls`, `undici`) cannot
492
- be imported.
493
- - `markSafeError` and `SAFE_ERROR` can only be imported in
494
- `src/infra/server/publicErrors/index.ts`.
495
- - `configureServerErrors` from `@solidjs/web`, the
496
- `@solidjs/web/server-functions` subpath and `observeRenderFailures` from the
497
- application's `renderIntegrity` module can only be imported in
498
- `src/infra/server/configureServerErrors/index.ts`.
499
- - A relative import goes up at most three levels. Use `@/` beyond that.
500
-
501
- Test files and `.d.ts` files are exempt from all of these except the relative
502
- import limit.
503
-
504
- ## Changing the preset
505
-
506
- `lint` and `fmt` are plain objects. Spread them and replace what the application
507
- needs:
508
-
509
- ```ts
510
- // vite.config.ts
511
- import { fmt } from '@evertondgn/solid-tooling/fmt'
512
- import { lint } from '@evertondgn/solid-tooling/lint'
513
- import { defineConfig } from 'vite-plus'
514
-
515
- export default defineConfig({
516
- fmt,
517
- lint: {
518
- ...lint,
519
- ignorePatterns: [...(lint.ignorePatterns ?? []), 'generated/**'],
520
- rules: { ...lint.rules, 'eslint/max-params': 'off' }
521
- }
522
- })
523
- ```
524
-
525
- Do not replace `lint.jsPlugins`. It registers the JavaScript plugins listed
526
- above, and a rule whose plugin is missing from it fails to resolve.
527
-
528
- To turn a rule off for some files only, add an entry to `lint.overrides` and
529
- keep the existing ones:
530
-
531
- ```ts
532
- overrides: [
533
- ...(lint.overrides ?? []),
534
- {
535
- files: ['src/tests/pages/Checkout/**'],
536
- rules: { 'project/test-filename': 'off' }
537
- }
538
- ]
539
- ```
540
-
541
- ## Entry points
542
-
543
- | Entry | Content |
544
- | ------------------------ | ------------------------------------------------------------------------- |
545
- | `./lint` | `lint`: the lint preset, with the plugins below registered |
546
- | `./fmt` | `fmt`: the formatter config |
547
- | `./tsconfig.base.json` | Compiler options, without application paths |
548
- | `./tsconfig.app.json` | The base plus the `types` and `include` of the boilerplate layout |
549
- | `./vite` | `defineSolidApp(options)`, the whole `vite.config.ts` of an application |
550
- | `./vitest` | `solidTest(options)`, the `test` block of `vite.config.ts` |
551
- | `./playwright` | `definePlaywrightConfig(options)`, the Playwright config |
552
- | `./vitest-setup/browser` | Setup file of the browser project, loaded by `./vitest` |
553
- | `./playwright-teardown` | Server log check, loaded by `./playwright` |
554
- | `./project-plugin` | The `project` rules |
555
- | `./backend-plugin` | The `backend` rules |
556
- | `./architecture-plugin` | The `architecture` rule |
557
- | `./solid-plugin` | Re-export of `eslint-plugin-solid` |
558
- | `./css-filename` | `cssFilenameError(path)`, the CSS naming check, for a script outside lint |
559
- | `./knip` | `defineKnipConfig(options)`, the Knip config |
560
- | `./stylelint` | `checkCss(root)` and `defineStylelintConfig(root)`, the CSS lint |
561
-
562
- An application imports `./vite`, which brings `./lint`, `./fmt` and `./vitest`
563
- along, `./playwright`, `./knip`, `./stylelint` and one of the TypeScript
564
- configs. An application that only lints imports `./lint` and `./fmt`. The plugin
565
- entries exist because Oxlint loads plugins by specifier, from the application;
566
- the setup and teardown entries are loaded by the test presets.
567
-
568
- ## Formatter
569
-
570
- `fmt` sets 80 columns, single quotes, no semicolons, no trailing commas, wrapped
571
- prose in Markdown and sorted imports. It ignores `public/`, `src/assets/`,
572
- generated route types, SVG and lock files.
573
-
574
- ## TypeScript base
575
-
576
- `tsconfig.base.json` targets ES2024 with bundler resolution, keeps JSX for the
577
- Solid compiler (`jsxImportSource: @solidjs/web`), emits nothing and turns on the
578
- unused code and unchecked index checks. It has no `paths`, `include` or `types`.
579
-
580
- `tsconfig.app.json` extends the base with the `types` of a boilerplate
581
- application and an `include` resolved from the application folder with
582
- `${configDir}`, which needs TypeScript 5.5 or later. Each entry of `types` comes
583
- from a package the application installs:
584
-
585
- | Entry of `types` | Package |
586
- | --------------------------------------- | --------------------------- |
587
- | `node` | `@types/node` |
588
- | `vite/client` | `vite` |
589
- | `vite-plus/test/globals` | `vite-plus` |
590
- | `@testing-library/jest-dom/vitest` | `@testing-library/jest-dom` |
591
- | `@solidjs/vite-plugin/boundary-modules` | `@solidjs/vite-plugin` |
592
- | `@solidjs/vite-plugin/virtual-modules` | `@solidjs/vite-plugin` |
593
-
594
- The application still declares its `paths`:
595
-
596
- ```json
597
- {
598
- "extends": "@evertondgn/solid-tooling/tsconfig.app.json",
599
- "compilerOptions": {
600
- "paths": { "@/*": ["./src/*"], "@paraglide/*": ["./paraglide/*"] }
601
- }
602
- }
603
- ```
604
-
605
- Playwright reads the `tsconfig.json` of the test files with its own loader,
606
- which does not expand `${configDir}`, so paths declared in the package would
607
- break the `@/` imports of the end-to-end tests.
608
-
609
- ## Known limits
610
-
611
- - The package ships compiled JavaScript. Node refuses to run TypeScript from
612
- `node_modules`, and Vite+ loads `vite.config.ts` in Node.
613
- - `project/test-filename` has no options. Test folders without a module, such as
614
- the page tests in `src/tests/pages/`, are listed inside the package with the
615
- names used in boilerplate_solidjs. For any other folder of that kind, turn the
616
- rule off in `lint.overrides`, as shown in
617
- [Changing the preset](#changing-the-preset).
618
- - The Paraglide plugin is always registered, so `@inlang/paraglide-js` has to be
619
- installed even in an application without translations.
620
- - Some rule messages point to `docs/architecture.md` and `AGENTS.md`. Those
621
- files belong to the application created from boilerplate_solidjs.
622
- - The test presets expect the boilerplate layout: tests named by suffix
623
- (`.node.test`, `.dom.test`, `.browser.test`, `.e2e.test`), page tests in
624
- `src/tests/pages/`, Paraglide output in `paraglide/` and `.env.test` at the
625
- root.
626
- - The Knip and CSS configs expect the same layout: pages in `src/routes/`,
627
- fixture routes in `src/tests/fixtures/` and the theme in `src/theme/`.
628
- - The Knip config ignores every unlisted dependency in its own file, not only
629
- this package.
630
- - `./vite` expects the same layout: its tasks run scripts in `tooling/`, and the
631
- Markdown rules need the locale prefix of the Paraglide `urlPatterns` in every
632
- URL. Nitro always uses the `vercel` preset. The plugin packages are pinned, so
633
- a new version of Solid, Nitro, the router or the icons plugin needs a package
634
- version tested with it.
635
-
636
- ## Versions
201
+ `HOST`, `PORT` and `BASE_URL_TEST` are optional; `PORT` produces a number.
202
+ Declare the runtime package in `dependencies` and keep the tooling in
203
+ `devDependencies`: Knip treats `env.ts` as production code. Extend `server` and
204
+ `client` with the application's own Standard Schema validators. The runtime
205
+ supplies Valibot for its fragment; declare a validator library in the
206
+ application only when its own code imports it. The optional SEO configuration
207
+ validates `VITE_SITE_URL` separately. An application without `env.ts` keeps
208
+ working, including client-only applications with no site URL.
209
+
210
+ The Solid plugin generates inferred types and rejects server env imports in the
211
+ client graph. The server virtual module bundles the fragment and validator; env
212
+ validation adds neither to the client. See the
213
+ [environment guide](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/app-config.md#optional-environment-validation)
214
+ for extension examples, boot validation and type generation.
215
+
216
+ ## How it is verified
217
+
218
+ <picture>
219
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/verified-dark.webp" />
220
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/verified-light.webp" />
221
+ <img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/verified-light.webp" alt="At this revision: 775 runtime and 394 application Vitest tests, 1169 combined; 164 fixture E2E cases and 155 production E2E cases, 319 enumerated. Installed tarballs check exports and builds with both Bun linkers. Release workflows use npm trusted publishing." width="800" />
222
+ </picture>
223
+
224
+ Package changes run against the complete boilerplate and the runtime package in
225
+ CI, with more than 1,000 Vitest tests and more than 300 end-to-end tests. Before
226
+ each release, the tarball test installs the packed package in a separate
227
+ application outside the workspace and checks its exports and lint rules.
228
+
229
+ The workflow publishes to npm with signed provenance through trusted publishing,
230
+ without a stored npm token. See the
231
+ [CI coverage](https://github.com/everton-dgn/solidjs_base/blob/main/docs/development.md#ci)
232
+ and the
233
+ [release process](https://github.com/everton-dgn/solidjs_base/blob/main/docs/releasing.md).
234
+
235
+ ## Reference
236
+
237
+ - [Lint rules and customization](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/lint.md)
238
+ - [Application config, plugins and tasks](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/app-config.md)
239
+ - [Vitest and Playwright](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/testing.md)
240
+ - [Knip and CSS](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/knip-and-css.md)
241
+ - [Commit messages and Git hooks](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/commits-and-hooks.md)
242
+ - [TypeScript and formatting](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/typescript-and-format.md)
243
+ - [Requirements, limits and versions](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/limits.md)
244
+
245
+ ## Versions and license
637
246
 
638
247
  The package follows semantic versioning. Below 1.0.0, a breaking change raises
639
- the minor version. Each release is listed in the
640
- [changelog](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-tooling/CHANGELOG.md).
641
-
642
- ## License
643
-
644
- MIT
248
+ the minor version. Read the
249
+ [changelog](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-tooling/CHANGELOG.md)
250
+ for each release.
251
+
252
+ [MIT](https://github.com/everton-dgn/solidjs_base/blob/main/LICENSE)
253
+
254
+ Publication is compiled into the preset and uses one build identity for the SSR
255
+ and artifact manifests. It no longer needs an application `extend` callback.
256
+ `publication/read-llms-index` exposes the compiled index reader for artifact
257
+ checks in Node. See
258
+ [ADR 0034](../../docs/ADRs/0034-runtime-markdown-publication.md) for independent
259
+ feature options, defaults, disabled-resource behavior and scale.