@evertondgn/solid-tooling 0.6.0 → 0.7.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/README.md +463 -77
- package/dist/vite.mjs +40 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,18 +7,24 @@
|
|
|
7
7
|
<picture>
|
|
8
8
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/hero-dark.webp" />
|
|
9
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" />
|
|
10
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/hero-light.webp" alt="Solid Base for SolidJS 2 RC and Vite+. Build your Solid app. Stop rebuilding its foundation. 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
11
|
</picture>
|
|
12
12
|
|
|
13
|
-
|
|
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 |
|
|
13
|
+
**The lint rules, tests, Git hooks and whole Vite+ config of your SolidJS 2
|
|
14
|
+
apps, as one dev dependency.**
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
Applications copied from a starter carry its tooling with them, and every fix to
|
|
17
|
+
the base has to be repeated by hand in each copy. This package holds that
|
|
18
|
+
tooling: an Oxlint preset with rules for your project layout, Oxfmt, TypeScript
|
|
19
|
+
configs, three Vitest projects, Playwright, Knip, a Stylelint policy,
|
|
20
|
+
commitlint, Git hooks and `defineSolidApp`, which returns the whole
|
|
21
|
+
`vite.config.ts` of a [Vite+](https://viteplus.dev/guide/) application. The fix
|
|
22
|
+
arrives when you update the dependency.
|
|
23
|
+
|
|
24
|
+
> SolidJS 2 is still a release candidate. The package is tested with
|
|
25
|
+
> `2.0.0-rc.21`, and its Solid, Nitro, router and icon plugins are pinned to the
|
|
26
|
+
> versions tested together. A new version of one of them needs a package version
|
|
27
|
+
> tested with it.
|
|
22
28
|
|
|
23
29
|
```bash
|
|
24
30
|
vp add -D @evertondgn/solid-tooling
|
|
@@ -26,9 +32,24 @@ vp add -D @evertondgn/solid-tooling
|
|
|
26
32
|
|
|
27
33
|
Built for applications that follow the
|
|
28
34
|
[boilerplate_solidjs](https://github.com/everton-dgn/boilerplate_solidjs)
|
|
29
|
-
layout.
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
layout. Start with lint and formatting in your existing Vite+ config, and adopt
|
|
36
|
+
the full application config when you are ready.
|
|
37
|
+
|
|
38
|
+
| Package | Role |
|
|
39
|
+
| --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
40
|
+
| [`@evertondgn/solid-tooling`](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-tooling/README.md) | Config, lint rules, tests, Git hooks, catalog generation, icons and fonts |
|
|
41
|
+
| [`@evertondgn/solid-runtime`](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-runtime/README.md) | Security headers, server errors, locale, theme, SEO, sitemaps, Markdown, env and fonts |
|
|
42
|
+
|
|
43
|
+
[Quick start](#quick-start) ·
|
|
44
|
+
[Less config](#the-configuration-you-stop-maintaining) ·
|
|
45
|
+
[Fewer dependencies](#fewer-tool-versions-in-each-manifest) ·
|
|
46
|
+
[App config](#your-application-config-in-one-call) ·
|
|
47
|
+
[Lint](#lint-rules-that-know-your-project) ·
|
|
48
|
+
[Tests](#tests-in-the-environment-each-one-needs) ·
|
|
49
|
+
[E2E](#end-to-end-tests-against-a-real-build) ·
|
|
50
|
+
[Knip](#unused-files-exports-and-dependencies) ·
|
|
51
|
+
[CSS](#a-css-policy-built-on-tokens) · [Hooks](#commit-messages-and-git-hooks) ·
|
|
52
|
+
[Entry points](#entry-points)
|
|
32
53
|
|
|
33
54
|
## Requirements
|
|
34
55
|
|
|
@@ -85,42 +106,84 @@ Run `vp lint`. The preset reports the export list:
|
|
|
85
106
|
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
107
|
```
|
|
87
108
|
|
|
88
|
-
|
|
109
|
+
<picture>
|
|
110
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/first-result-dark.webp" />
|
|
111
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/first-result-light.webp" />
|
|
112
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/first-result-light.webp" alt="The example ends with export { example } at line 3. vp lint reports project(no-export-list) at line 3, column 1 and asks for an export on the declaration. The corrected export const example = 1 passes that rule." width="800" />
|
|
113
|
+
</picture>
|
|
89
114
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
115
|
+
Replace the list with `export const example = 1` and the rule passes. `fmt` sets
|
|
116
|
+
80 columns, single quotes, no semicolons, no trailing commas, wrapped Markdown
|
|
117
|
+
prose and sorted imports. See the
|
|
118
|
+
[formatter](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/typescript-and-format.md#formatter)
|
|
119
|
+
and the
|
|
120
|
+
[TypeScript configs](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/typescript-and-format.md#typescript-base).
|
|
121
|
+
|
|
122
|
+
## The configuration you stop maintaining
|
|
93
123
|
|
|
94
124
|
<picture>
|
|
95
125
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/before-after-dark.webp" />
|
|
96
126
|
<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
|
|
127
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/before-after-light.webp" alt="About 87 percent fewer lines across five configuration areas, from 945 to 125: Vite 427 to 48, 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
128
|
</picture>
|
|
99
129
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
[
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
130
|
+
The original starter kept 945 lines of configuration in five areas. The same
|
|
131
|
+
application on this package keeps 125, about 87% fewer. The shared
|
|
132
|
+
implementation lives in the package, where one fix serves every application.
|
|
133
|
+
|
|
134
|
+
| Configuration | Original lines | With the package |
|
|
135
|
+
| --------------------------------------------------------------------------------------------------------------- | -------------: | ---------------: |
|
|
136
|
+
| [Vite](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/vite.config.ts) | 427 | 48 |
|
|
137
|
+
| [Playwright](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/playwright.config.ts) | 173 | 17 |
|
|
138
|
+
| [Knip](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/tooling/knip.ts) | 129 | 40 |
|
|
139
|
+
| [TypeScript](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/tsconfig.json) | 45 | 9 |
|
|
140
|
+
| [Stylelint caller](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/tooling/css/check.ts) | 171 | 11 |
|
|
141
|
+
|
|
142
|
+
Counts include blank lines and comments. The baseline is the
|
|
143
|
+
[original starter at 6145493](https://github.com/everton-dgn/boilerplate_solidjs/tree/61454937472d0faa1b4fab985fd7c5da968aa9a6),
|
|
144
|
+
whose Playwright and Stylelint configs lived in `tooling/playwright.ts` and
|
|
145
|
+
`tooling/css/stylelint.config.mjs`. Compare its
|
|
146
|
+
[`vite.config.ts`](https://github.com/everton-dgn/boilerplate_solidjs/blob/61454937472d0faa1b4fab985fd7c5da968aa9a6/vite.config.ts)
|
|
147
|
+
with the application's. The Stylelint replacement is an application script that
|
|
148
|
+
calls the packaged policy.
|
|
119
149
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
150
|
+
<picture>
|
|
151
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/fix-once-dark.webp" />
|
|
152
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/fix-once-light.webp" />
|
|
153
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/fix-once-light.webp" alt="Copied tooling and runtime drift between applications A, B and C. With Solid Base, the apps keep thin configs and consume solid-tooling and solid-runtime. Shared fixes arrive through vp update; application-specific code stays with each app." width="800" />
|
|
154
|
+
</picture>
|
|
155
|
+
|
|
156
|
+
## Fewer tool versions in each manifest
|
|
157
|
+
|
|
158
|
+
<picture>
|
|
159
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/libraries-dark.webp" />
|
|
160
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/libraries-light.webp" />
|
|
161
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/libraries-light.webp" alt="Direct manifest declarations before and after: boilerplate 28 to 14, client-only 16 to 5, SSR plain 17 to 5, SSR i18n 19 to 7, lint consumer 6 to 3." width="800" />
|
|
162
|
+
</picture>
|
|
163
|
+
|
|
164
|
+
The package installs the build, test, type-check and hook tools it calls, at the
|
|
165
|
+
versions it tests, and runs them from its own installation, including with Bun's
|
|
166
|
+
isolated linker. Your manifest keeps only what your own code imports, plus Vite+
|
|
167
|
+
and its Vite alias.
|
|
168
|
+
|
|
169
|
+
| Application | Direct declarations before | Now | Fewer |
|
|
170
|
+
| ----------------------------------------------------------------------------------------------------------- | -------------------------: | --: | ----: |
|
|
171
|
+
| [Boilerplate copy](https://github.com/everton-dgn/solidjs_base/blob/main/apps/boilerplate/package.json) | 28 | 14 | 14 |
|
|
172
|
+
| [Client-only](https://github.com/everton-dgn/solidjs_base/blob/main/fixtures/apps/client-only/package.json) | 16 | 5 | 11 |
|
|
173
|
+
| [SSR plain](https://github.com/everton-dgn/solidjs_base/blob/main/fixtures/apps/ssr-plain/package.json) | 17 | 5 | 12 |
|
|
174
|
+
| [SSR i18n](https://github.com/everton-dgn/solidjs_base/blob/main/fixtures/apps/ssr-i18n/package.json) | 19 | 7 | 12 |
|
|
175
|
+
| [Lint consumer](https://github.com/everton-dgn/solidjs_base/blob/main/fixtures/consumer/package.json) | 6 | 3 | 3 |
|
|
176
|
+
|
|
177
|
+
Counts combine `dependencies` and `devDependencies`, without overrides or
|
|
178
|
+
transitive packages. The fixture counts leave out the two package tarballs that
|
|
179
|
+
the installed test harness adds.
|
|
180
|
+
|
|
181
|
+
Fewer declarations do not mean a smaller install. The tooling also installs the
|
|
182
|
+
tools of features you may not use: in the
|
|
183
|
+
[measurement of that decision](https://github.com/everton-dgn/solidjs_base/blob/main/docs/ADRs/0027-packaged-tool-dependencies.md),
|
|
184
|
+
the `node_modules` of a fresh client-only application grew by 8.41% with the
|
|
185
|
+
hoisted linker and 8.69% with the isolated one. Build audits check that these
|
|
186
|
+
tools stay out of the application bundles.
|
|
124
187
|
|
|
125
188
|
## Your application config in one call
|
|
126
189
|
|
|
@@ -139,39 +202,283 @@ export default defineSolidApp({
|
|
|
139
202
|
})
|
|
140
203
|
```
|
|
141
204
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
205
|
+
That call registers the Solid plugin with SSR and server functions, file-system
|
|
206
|
+
routing with route types, icons, Nitro with the Vercel preset, the headers of
|
|
207
|
+
the static files, Lightning CSS with content-hashed CSS Modules class names, and
|
|
208
|
+
the dev server and preview on the `HOST` and `PORT` of `.env`. You keep your
|
|
209
|
+
middleware and header values. The plugins are package dependencies pinned to the
|
|
210
|
+
tested versions.
|
|
146
211
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
212
|
+
<picture>
|
|
213
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/only-what-you-use-dark.webp" />
|
|
214
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/only-what-you-use-light.webp" />
|
|
215
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/only-what-you-use-light.webp" alt="A client-only vite.config.ts with defineSolidApp, root and ssr: false. No translation project, theme imports, env.ts, fonts option or SEO are needed, and the build has client output only, with no Nitro or server bundle." width="800" />
|
|
216
|
+
</picture>
|
|
152
217
|
|
|
153
|
-
|
|
218
|
+
Each feature turns on only when the application uses it:
|
|
219
|
+
|
|
220
|
+
| Feature | Selection |
|
|
221
|
+
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
222
|
+
| Client-only build | Set `ssr: false` and omit SSR options such as `middleware` and `securityHeaders`; the build has no Nitro or server bundle and accepts a relative `./` base |
|
|
223
|
+
| Publication headers | Set `seo.markdown`, `seo.llms` and `seo.sitemap` one by one; `seo.llmsFull` also needs `seo.llms` and `seo.markdown.static` |
|
|
224
|
+
| Translations | `project.inlang/settings.json` enables the generation task and browser test setup; the lint plugin loads only where Paraglide resolves |
|
|
225
|
+
|
|
226
|
+
When the standard does not fit, change it without a fork: `extend` adds plugins
|
|
227
|
+
and Nitro modules, `tasks` adds or replaces a `vp run` task, `routeRules`,
|
|
228
|
+
`publicAssets` and `staticPaths` adjust Nitro and the static headers,
|
|
229
|
+
`workspace` places the app in a monorepo, and `mergeConfig` merges anything else
|
|
230
|
+
over the result.
|
|
231
|
+
|
|
232
|
+
The preset also defines the `vp run` tasks of the boilerplate layout:
|
|
233
|
+
`i18n-generate`, `lint-css`, `dead-code-project`, `lint-project`,
|
|
234
|
+
`check-project`, `typecheck-node` and `test-tooling`. The `knip`, `tsc`,
|
|
235
|
+
`playwright`, `lefthook` and `commitlint` tasks run the package-owned binaries,
|
|
236
|
+
including with an isolated installation. See
|
|
154
237
|
[all options and extension points](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/app-config.md)
|
|
155
238
|
and the
|
|
156
239
|
[known limits](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/limits.md#known-limits).
|
|
157
240
|
|
|
158
|
-
##
|
|
241
|
+
## Lint rules that know your project
|
|
242
|
+
|
|
243
|
+
The preset turns on the Oxlint plugins `import`, `jsx-a11y`, `node`, `oxc`,
|
|
244
|
+
`promise`, `typescript`, `unicorn` and `vitest`, the `solid` and `vite-plus`
|
|
245
|
+
plugins and three plugins of this package, plus `paraglide` when it resolves.
|
|
246
|
+
Type-aware rules and type checking are on. Warnings fail the run, and an unused
|
|
247
|
+
disable directive is an error. Every rule is listed by name, so an Oxlint update
|
|
248
|
+
does not add rules on its own.
|
|
249
|
+
|
|
250
|
+
The rules of this package catch what a generic preset cannot see:
|
|
251
|
+
|
|
252
|
+
| Rule | What it enforces |
|
|
253
|
+
| ---------------------------- | --------------------------------------------------------------------------------------------------- |
|
|
254
|
+
| `project/css-modules-import` | A CSS Module is imported as the default binding `S` |
|
|
255
|
+
| `project/css-filename` | A CSS file is named `styles.module.css`, or `camelCase.css` inside `src/theme/` |
|
|
256
|
+
| `project/test-filename` | A test sits in `__tests__` next to its module, named after it and its environment |
|
|
257
|
+
| `project/no-export-list` | Exports sit on the declaration |
|
|
258
|
+
| `project/seo-module` | A route `seo.ts` exports only `seo` and imports no route values |
|
|
259
|
+
| `architecture/layer-imports` | Lower layers do not import upper ones, and production code does not import tests or `tooling/` |
|
|
260
|
+
| `backend/*` | No `console`, `fetch` only in `requestJson`, no Node transports, no `node_modules` paths in imports |
|
|
261
|
+
|
|
262
|
+
<picture>
|
|
263
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/layers-dark.webp" />
|
|
264
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/layers-light.webp" />
|
|
265
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/layers-light.webp" alt="architecture/layer-imports: imports only point down, from routes and entry files through organisms, molecules, atoms and primitives to the base layer. Below, vp lint on a copy of the boilerplate where the PageBadge atom imports a molecule: src/components/atoms/PageBadge/index.tsx:3:1: error architecture(layer-imports): Layer atoms must not depend on molecules (src/components/molecules/PageHero/index.tsx). See the layer rules in docs/architecture.md. Production code cannot import tests or tooling/ either." width="800" />
|
|
266
|
+
</picture>
|
|
267
|
+
|
|
268
|
+
The layer rule keeps the dependency direction of the UI. The base layer
|
|
269
|
+
(`@types`, `constants`, `helpers`, `data`, `infra`, `theme`, `i18n` and
|
|
270
|
+
`paraglide/`) imports no primitives, components, routes or entry files.
|
|
271
|
+
Primitives import no components or routes. Atoms do not import molecules or
|
|
272
|
+
organisms, and molecules do not import organisms. An import in the wrong
|
|
273
|
+
direction fails `vp lint` before review.
|
|
274
|
+
|
|
275
|
+
The backend rules keep outgoing requests in one module. Inside `src/`, `fetch`,
|
|
276
|
+
`XMLHttpRequest`, `WebSocket` and `EventSource` are refused outside
|
|
277
|
+
`src/infra/server/requestJson/index.ts`, `console` is refused, and the server
|
|
278
|
+
error configurator can only be imported in its setup file. See
|
|
279
|
+
[all rules and customization](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/lint.md).
|
|
280
|
+
|
|
281
|
+
## Tests in the environment each one needs
|
|
282
|
+
|
|
283
|
+
<picture>
|
|
284
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/vitest-projects-dark.webp" />
|
|
285
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/vitest-projects-light.webp" />
|
|
286
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/vitest-projects-light.webp" alt="The three Vitest projects of solidTest with their file globs and environments. In apps/boilerplate, 185 tests passed: 68 node tests in 12 files, 87 dom tests with happy-dom in 13 files and 30 browser tests with Chromium in 7 files. Coverage thresholds: 80% for lines, functions and statements, 75% for branches." width="800" />
|
|
287
|
+
</picture>
|
|
288
|
+
|
|
289
|
+
The file name picks the environment, so a server test, a component test and a
|
|
290
|
+
real-browser test live in the same repository with no extra config. In the
|
|
291
|
+
boilerplate, `vp test run` passed 185 tests in 32 files: 68 `node` tests in 12
|
|
292
|
+
files, 87 `dom` in 13 and 30 `browser` in 7.
|
|
293
|
+
|
|
294
|
+
| Project | Files | Environment |
|
|
295
|
+
| --------- | -------------------------------- | ------------------------------------------------ |
|
|
296
|
+
| `node` | `src/**/*.node.test.{ts,tsx}` | Node, with stand-ins for the build-only modules |
|
|
297
|
+
| `dom` | `src/**/*.dom.test.{ts,tsx}` | happy-dom, at the URL of `domUrl` |
|
|
298
|
+
| `browser` | `src/**/*.browser.test.{ts,tsx}` | Chromium through Playwright, with the CSS loaded |
|
|
299
|
+
|
|
300
|
+
The preset sets coverage thresholds of 80% for lines, functions and statements
|
|
301
|
+
and 75% for branches, the reporters and the CI workers. It resets the Paraglide
|
|
302
|
+
locale before each browser test and resolves packages that ship TypeScript
|
|
303
|
+
source, such as the runtime, under the `solid` condition. `defineSolidApp`
|
|
304
|
+
already calls `solidTest`; an application with its own Vite config imports it
|
|
305
|
+
from `./vitest`. See
|
|
306
|
+
[Vitest and Playwright](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/testing.md).
|
|
307
|
+
|
|
308
|
+
## End-to-end tests against a real build
|
|
309
|
+
|
|
310
|
+
<picture>
|
|
311
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/e2e-coverage-dark.webp" />
|
|
312
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/e2e-coverage-light.webp" />
|
|
313
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/e2e-coverage-light.webp" alt="The Playwright inventory of apps/boilerplate: 319 E2E cases across 15 areas, 164 in the E2E build and 155 in the production build. AgentReadiness 77, I18n 40, Home 36, SeoIndexes 29, Markdown 27, BackendError 25, BuildOutput 22, OutsideError 18, Hydration 18, UiKit 8, OutdatedPage 7, StructuredData 6, FragmentCss 2, LateRedirect 2 and NotFound 2. Enumerated with playwright test --list, without running them." width="800" />
|
|
314
|
+
</picture>
|
|
315
|
+
|
|
316
|
+
`definePlaywrightConfig` reads `BASE_URL_TEST` from `.env.test`, builds the
|
|
317
|
+
application, starts the preview and runs the suite against it: `e2e` mode for
|
|
318
|
+
the fixture routes, or the production build with `TEST_PRODUCTION_ROUTES=true`.
|
|
319
|
+
`TEST_PREBUILT=true` reuses an existing production build. Serial suites run in
|
|
320
|
+
their own projects: `markdown` with one worker, `publicationLoad` alone against
|
|
321
|
+
two servers, and `serverLogs` last, as the teardown of the others.
|
|
322
|
+
|
|
323
|
+
When the suite ends, `./playwright-teardown` checks the server log for private
|
|
324
|
+
markers, so a test run also fails when a server error leaks its details into the
|
|
325
|
+
log.
|
|
326
|
+
|
|
327
|
+
In the boilerplate, `vp run playwright test --list` counts 319 cases in 15 page
|
|
328
|
+
areas, 164 in 26 files for the E2E build and 155 in 12 files for the production
|
|
329
|
+
build; the figure above breaks them down by area.
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
// playwright.config.ts
|
|
333
|
+
import { definePlaywrightConfig } from '@evertondgn/solid-tooling/playwright'
|
|
334
|
+
|
|
335
|
+
export default definePlaywrightConfig({ root: import.meta.dirname })
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Unused files, exports and dependencies
|
|
339
|
+
|
|
340
|
+
<picture>
|
|
341
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/dead-code-dark.webp" />
|
|
342
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/dead-code-light.webp" />
|
|
343
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/dead-code-light.webp" alt="Knip output on a copy of the boilerplate with an unused file, dependency and export added. Unused files (1): src/helpers/formatPrice/index.ts. Unused dependencies (1): date-fns at package.json:45:6. Unused exports (1): THEME_COOKIE_NAME at src/constants/theme.ts:6:14. The first pass fails, so vp run dead-code-project stops before the --strict pass." width="800" />
|
|
344
|
+
</picture>
|
|
345
|
+
|
|
346
|
+
A helper nobody calls, an export nobody imports and a dependency nobody uses
|
|
347
|
+
stop the push, and the report says where each one is. `defineKnipConfig` from
|
|
348
|
+
`./knip` gives Knip the entries of a Solid app: the server and client entries,
|
|
349
|
+
the middleware, `env.ts`, the Paraglide runtime, and every page and HTTP handler
|
|
350
|
+
that file-system routing finds. It turns off Knip's own routing plugin, which
|
|
351
|
+
takes every file of `src/routes/` as an entry, so an unused helper next to a
|
|
352
|
+
route is reported. Configuration hints are errors, and
|
|
353
|
+
`vp run dead-code-project` runs Knip twice, the second time with `--strict`. The
|
|
354
|
+
`pre-push` hook below runs it before the code leaves your machine.
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
// tooling/knip.ts
|
|
358
|
+
import path from 'node:path'
|
|
359
|
+
|
|
360
|
+
import { defineKnipConfig } from '@evertondgn/solid-tooling/knip'
|
|
361
|
+
|
|
362
|
+
export default defineKnipConfig({
|
|
363
|
+
root: path.resolve(import.meta.dirname, '..'),
|
|
364
|
+
ignoreDependencies: ['server-only']
|
|
365
|
+
})
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## A CSS policy built on tokens
|
|
369
|
+
|
|
370
|
+
<picture>
|
|
371
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/css-tokens-dark.webp" />
|
|
372
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/css-tokens-light.webp" />
|
|
373
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/css-tokens-light.webp" alt="In styles.module.css, color: #0b1525 is refused with the Stylelint message to use only var() tokens, and color: var(--color-foreground) passes. The token files of the boilerplate define 36 color, 11 font, 7 shadow, 6 grid, 5 radius and 3 z-index custom properties." width="800" />
|
|
374
|
+
</picture>
|
|
375
|
+
|
|
376
|
+
Outside `src/theme/`, colors, gradients, radii, shadows, font sizes and weights
|
|
377
|
+
and `z-index` must come from tokens with `var()`, from the matching token
|
|
378
|
+
family. A literal color is an error, so the palette is defined in the theme
|
|
379
|
+
files. Inside `src/theme/`, the theme defines the values with `oklch()`,
|
|
380
|
+
`oklab()`, `color-mix()` and `light-dark()`.
|
|
381
|
+
|
|
382
|
+
The policy also requires snake_case classes and at most two levels of nesting,
|
|
383
|
+
refuses unknown properties, values, units and selectors, checks that each
|
|
384
|
+
`var()` resolves to a token file, and accepts an exception only with a
|
|
385
|
+
`stylelint-disable` comment that gives the reason. `checkCss(root)` from
|
|
386
|
+
`./stylelint` runs it and checks CSS file names; the boilerplate's caller has 11
|
|
387
|
+
lines. The boilerplate's token files define 36 color, 11 font, 7 shadow, 6 grid,
|
|
388
|
+
5 radius and 3 z-index custom properties. See
|
|
389
|
+
[Knip and CSS](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/knip-and-css.md).
|
|
390
|
+
|
|
391
|
+
## Commit messages and Git hooks
|
|
392
|
+
|
|
393
|
+
<picture>
|
|
394
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/git-hooks-dark.webp" />
|
|
395
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/git-hooks-light.webp" />
|
|
396
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/git-hooks-light.webp" alt="The shared lefthook.yml: commit-msg runs commitlint with Conventional Commits and a 100-character header; pre-commit runs check:fix on the staged files and the kingfisher secret scan when installed, and skips merge and rebase; pre-push runs check:ci, typecheck:node and test:ci, then test:tooling and dead-code in parallel, and stops at the first failure." width="800" />
|
|
397
|
+
</picture>
|
|
398
|
+
|
|
399
|
+
The shared hooks check a change before it reaches the remote:
|
|
400
|
+
|
|
401
|
+
| Hook | Jobs |
|
|
402
|
+
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
403
|
+
| `commit-msg` | `commitlint` on the message |
|
|
404
|
+
| `pre-commit` | `check:fix` on the staged files, staged again after the fix, and `scan:secrets --staged` when `kingfisher` is installed. Skipped in merge and rebase |
|
|
405
|
+
| `pre-push` | `check:ci`, `typecheck:node` and `test:ci` in order, then `test:tooling` and `dead-code` together; the first failure stops |
|
|
406
|
+
|
|
407
|
+
`./commitlint` applies the Conventional Commits rules with the header limited to
|
|
408
|
+
100 characters and a blank line before the footer. Lefthook and the commitlint
|
|
409
|
+
CLI come with the package, so the application declares neither. Extend the
|
|
410
|
+
shared file from `.lefthook.yml`, and override a shared job by name in
|
|
411
|
+
`lefthook-local.yml`, committed for everyone or kept on one machine:
|
|
412
|
+
|
|
413
|
+
```yaml
|
|
414
|
+
# .lefthook.yml
|
|
415
|
+
extends:
|
|
416
|
+
- node_modules/@evertondgn/solid-tooling/lefthook.yml
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
See
|
|
420
|
+
[Commit messages and Git hooks](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/commits-and-hooks.md).
|
|
421
|
+
|
|
422
|
+
## Translations, icons and fonts as data
|
|
423
|
+
|
|
424
|
+
<picture>
|
|
425
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/i18n-dark.webp" />
|
|
426
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/i18n-light.webp" />
|
|
427
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/i18n-light.webp" alt="A project.inlang settings excerpt with base locale fr and locales fr, de, it and ja. Catalogs stay beside each feature; validation, compilation and localization produce translated pages, URL helpers, redirects, cookies and navigation. Without a translation project, URLs stay unprefixed." width="800" />
|
|
428
|
+
</picture>
|
|
429
|
+
|
|
430
|
+
With `project.inlang/settings.json`, the packaged generator reads the catalogs
|
|
431
|
+
beside each feature, `src/**/i18n/<locale>.json`, and compiles Paraglide in
|
|
432
|
+
development, builds and tests. A missing translation, a duplicate ID or an
|
|
433
|
+
invalid message fails with the file and the key. The locales come from your
|
|
434
|
+
settings, with no fixed set. Without the file, no generator or i18n plugin
|
|
435
|
+
enters the build.
|
|
436
|
+
|
|
437
|
+
<picture>
|
|
438
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/icons-dark.webp" />
|
|
439
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/icons-light.webp" />
|
|
440
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/icons-light.webp" alt="solid.svg in src/assets/images becomes a Solid component. The icons option maps the my-images collection to that folder, the component imports ~icons/my-images/solid, and the preset adds aria-hidden=true; the icon-only control supplies its accessible label." width="800" />
|
|
441
|
+
</picture>
|
|
442
|
+
|
|
443
|
+
Icons from Iconify collections, or your own SVG folders mapped with the `icons`
|
|
444
|
+
option, become Solid components through `unplugin-icons`, with `aria-hidden` on
|
|
445
|
+
every icon. The application does not declare the plugin.
|
|
446
|
+
|
|
447
|
+
<picture>
|
|
448
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/fonts-dark.webp" />
|
|
449
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/fonts-light.webp" />
|
|
450
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/fonts-light.webp" alt="One font asset list in defineSolidApp produces external @font-face CSS with content-hashed URLs, deduplicated files and matching preload links. SSR renders FontLinks in the Document; client-only apps receive the links in index.html; without fonts, nothing is generated." width="800" />
|
|
451
|
+
</picture>
|
|
159
452
|
|
|
160
453
|
Pass a data-only `fonts` array to `defineSolidApp` to generate external
|
|
161
454
|
`@font-face` CSS and matching preloads for application-owned files. SSR uses
|
|
162
455
|
`FontLinks` from `@evertondgn/solid-runtime/fonts/font-links` in the Document
|
|
163
|
-
head; client-only applications receive both links in `index.html
|
|
164
|
-
|
|
456
|
+
head; client-only applications receive both links in `index.html`, also with a
|
|
457
|
+
relative `./` base for `file://` and app shells. Leave `fonts` out and nothing
|
|
458
|
+
is generated. Typography tokens stay in the app. See the
|
|
165
459
|
[font API and migration examples](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/fonts.md).
|
|
166
460
|
|
|
167
|
-
##
|
|
461
|
+
## SEO configured as data
|
|
462
|
+
|
|
463
|
+
<picture>
|
|
464
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/seo-dark.webp" />
|
|
465
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/seo-light.webp" />
|
|
466
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/seo-light.webp" alt="Three independent SEO parts. Head: createSeo with inherited route metadata, canonical and social tags and escaped JSON-LD. Robots: an explicit route with a serializable crawl policy. Sitemap: createSitemapRoutes with arrays or bounded partition reads under the shared publication controller. All work with or without i18n." width="800" />
|
|
467
|
+
</picture>
|
|
468
|
+
|
|
469
|
+
Robots, sitemap headers, Markdown and the llms indexes are options of
|
|
470
|
+
`defineSolidApp` written as plain data, validated when the config loads. None of
|
|
471
|
+
them turns on another. Only `llmsFull` has prerequisites: the full file is built
|
|
472
|
+
from the static Markdown, so it needs `llms` and `markdown: { static: true }`,
|
|
473
|
+
and the config fails to load without them. The site URL becomes required once
|
|
474
|
+
`seo` is set, as an HTTP(S) origin with no path, query, fragment or credentials;
|
|
475
|
+
leave `seo` out and no origin is read.
|
|
168
476
|
|
|
169
477
|
For SSR,
|
|
170
478
|
`seo: { robots: { groups, sitemapPaths, cacheControl }, sitemap: true }`
|
|
171
479
|
configures the runtime robots route using serializable data. `originEnv`
|
|
172
|
-
defaults to `VITE_SITE_URL
|
|
173
|
-
|
|
174
|
-
the runtime origin entry is imported. No SEO means no required origin.
|
|
480
|
+
defaults to `VITE_SITE_URL`. The preset validates it when SEO is enabled or the
|
|
481
|
+
runtime origin entry is imported.
|
|
175
482
|
|
|
176
483
|
Pass `site` directly to the runtime `createSeo` primitive. A meta/JSON-LD-only
|
|
177
484
|
application can omit `seo`, provide its own `site.url` and omit robots entirely.
|
|
@@ -183,12 +490,36 @@ and list the root in `robots.sitemapPaths` to advertise it. To remove sitemap,
|
|
|
183
490
|
remove its routes and server binding, omit its array metadata, omit
|
|
184
491
|
`sitemapPaths`, and omit or disable `seo.sitemap`. Robots can stay enabled. The
|
|
185
492
|
preset does not discover executable source registries or install routes. See the
|
|
186
|
-
[runtime SEO API](
|
|
187
|
-
one-line route and examples with and without translations.
|
|
493
|
+
[runtime SEO API](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-runtime/README.md#optional-seo)
|
|
494
|
+
for factories, the one-line route and examples with and without translations.
|
|
495
|
+
|
|
496
|
+
### Publication artifacts
|
|
497
|
+
|
|
498
|
+
Crawlers get files, not renders. The build writes what you turn on: a `.md` copy
|
|
499
|
+
of each opted-in page with `markdown: { static: true }`, `llms.txt` with `llms`,
|
|
500
|
+
`llms-full.txt` with `llmsFull`, and the sitemap XML with
|
|
501
|
+
`sitemap: { static: true }`. A bad artifact fails the build instead of reaching
|
|
502
|
+
production: a `.md` file that is empty, not UTF-8 or still an HTML document, an
|
|
503
|
+
index or sitemap file over its byte budget, an `llms.txt` whose link to
|
|
504
|
+
`llms-full.txt` disagrees with the files built, a static page that resolves to
|
|
505
|
+
another route, or a Markdown list or sitemap inventory from a different build
|
|
506
|
+
than the SSR bundle. Your config needs no `extend` callback for this.
|
|
507
|
+
`publication/read-llms-index` exposes the compiled index reader for artifact
|
|
508
|
+
checks in Node. See
|
|
509
|
+
[ADR 0034](https://github.com/everton-dgn/solidjs_base/blob/main/docs/ADRs/0034-runtime-markdown-publication.md)
|
|
510
|
+
for the feature options, defaults, disabled-resource behavior and scale.
|
|
188
511
|
|
|
189
512
|
## Optional environment validation
|
|
190
513
|
|
|
191
|
-
|
|
514
|
+
<picture>
|
|
515
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/env-dark.webp" />
|
|
516
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/env-light.webp" />
|
|
517
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/env-light.webp" alt="An optional env.ts spreads serverEnv: HOST string or undefined, PORT number or undefined, BASE_URL_TEST string or undefined. Server virtual imports validate at initialization and fail the build from client code. Public client values validate at build time with inferred types and no validator shipped. No env requirements? Omit env.ts." width="800" />
|
|
518
|
+
</picture>
|
|
519
|
+
|
|
520
|
+
A missing or malformed value fails where it enters: when the server code that
|
|
521
|
+
imports it loads, or at build time for a public value. An SSR application can
|
|
522
|
+
add `env.ts` with the preset's optional validators:
|
|
192
523
|
|
|
193
524
|
```ts
|
|
194
525
|
import { serverEnv } from '@evertondgn/solid-runtime/env'
|
|
@@ -218,21 +549,81 @@ for extension examples, boot validation and type generation.
|
|
|
218
549
|
<picture>
|
|
219
550
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/verified-dark.webp" />
|
|
220
551
|
<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="
|
|
552
|
+
<img src="https://raw.githubusercontent.com/everton-dgn/solidjs_base/main/docs/assets/readme/verified-light.webp" alt="Current revision: 1,186 Vitest tests passed, 1,001 in the runtime and 185 in the boilerplate app; 319 E2E cases listed, 164 for the E2E build and 155 for the production build. Before each release the tarball is installed in a separate application and its exports and lint rules are checked. Release workflows publish with trusted publishing and signed npm provenance, with no stored npm token." width="800" />
|
|
222
553
|
</picture>
|
|
223
554
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
The
|
|
230
|
-
|
|
555
|
+
At this revision, 1,186 Vitest tests passed: 1,001 in 100 files of the runtime
|
|
556
|
+
package and 185 in 32 files of the boilerplate app. `playwright test --list`
|
|
557
|
+
counts 319 E2E cases in the app, 164 for the E2E build and 155 for the
|
|
558
|
+
production build.
|
|
559
|
+
|
|
560
|
+
- The package's own tests, `vp run test`, run with `node --test` against
|
|
561
|
+
fixtures in temporary folders: 268 `test` and `it` calls in 39 files, counted
|
|
562
|
+
in source.
|
|
563
|
+
- The tarball test packs the package, installs it in a separate application
|
|
564
|
+
outside the workspace and checks that lint applies the plugins, that the
|
|
565
|
+
application extends the shared hooks and commitlint config, and that the
|
|
566
|
+
fixture declares the workspace versions.
|
|
567
|
+
- The installed scenarios install the packed tooling and runtime in the
|
|
568
|
+
[three fixture applications](https://github.com/everton-dgn/solidjs_base/tree/main/fixtures/apps)
|
|
569
|
+
with Bun's `hoisted` and `isolated` linkers and build them. The matrix
|
|
570
|
+
enumerates 14 application cases: 3 client-only, 9 SSR and 2 translated SSR.
|
|
571
|
+
They fail when a disabled feature leaves its modules in the bundle.
|
|
572
|
+
- The runtime package is linted with this package's preset, loaded from its
|
|
573
|
+
sources.
|
|
574
|
+
|
|
575
|
+
`vp run validate` at the root runs the build, checks, dead code, package tests,
|
|
576
|
+
tarball tests and installed scenarios, as the publish job does. CI selects jobs
|
|
577
|
+
by changed paths, and a package change runs the packages and the complete
|
|
578
|
+
boilerplate app. The workflow publishes to npm through trusted publishing, with
|
|
579
|
+
signed provenance and no stored npm token. See the
|
|
231
580
|
[CI coverage](https://github.com/everton-dgn/solidjs_base/blob/main/docs/development.md#ci)
|
|
232
581
|
and the
|
|
233
582
|
[release process](https://github.com/everton-dgn/solidjs_base/blob/main/docs/releasing.md).
|
|
234
583
|
|
|
235
|
-
##
|
|
584
|
+
## Entry points
|
|
585
|
+
|
|
586
|
+
| Entry | Content |
|
|
587
|
+
| ------------------------------- | -------------------------------------------------------------------------------- |
|
|
588
|
+
| `./vite` | `defineSolidApp(options)`, the whole `vite.config.ts` of an application |
|
|
589
|
+
| `./lint` | `lint`: the lint preset, with the plugins below registered |
|
|
590
|
+
| `./fmt` | `fmt`: the formatter config |
|
|
591
|
+
| `./tsconfig.base.json` | Compiler options, without application paths |
|
|
592
|
+
| `./tsconfig.app.json` | The base plus packaged type references and the boilerplate `include` |
|
|
593
|
+
| `./app-env` | Type references loaded by `tsconfig.app.json` |
|
|
594
|
+
| `./virtual-modules` | Declarations of the `virtual:solid-app/*` modules, loaded by `tsconfig.app.json` |
|
|
595
|
+
| `./vitest` | `solidTest(options)`, the `test` block of `vite.config.ts` |
|
|
596
|
+
| `./vitest-setup/browser` | Setup file of the browser project, loaded by `./vitest` |
|
|
597
|
+
| `./playwright` | `definePlaywrightConfig(options)`, the Playwright config |
|
|
598
|
+
| `./playwright-teardown` | Server log check, loaded by `./playwright` |
|
|
599
|
+
| `./project-plugin` | The `project` rules |
|
|
600
|
+
| `./backend-plugin` | The `backend` rules |
|
|
601
|
+
| `./architecture-plugin` | The `architecture` rule |
|
|
602
|
+
| `./solid-plugin` | Re-export of `eslint-plugin-solid`, resolved from the package |
|
|
603
|
+
| `./css-filename` | `cssFilenameError(path)`, the CSS naming check, for a script outside lint |
|
|
604
|
+
| `./knip` | `defineKnipConfig(options)`, the Knip config |
|
|
605
|
+
| `./stylelint` | `checkCss(root)` and `defineStylelintConfig(root)`, the CSS lint |
|
|
606
|
+
| `./commitlint` | The commitlint config |
|
|
607
|
+
| `./lefthook.yml` | The Git hooks, extended from the application's `.lefthook.yml` |
|
|
608
|
+
| `./cli` | Command entry for packaged Knip, TypeScript, Playwright, Lefthook and commitlint |
|
|
609
|
+
| `./i18n-generate` | Compiled catalog generator executed by the preset's `i18n-generate` task |
|
|
610
|
+
| `./publication/read-llms-index` | Compiled reader of the llms index, for artifact checks in Node |
|
|
611
|
+
| `./package.json` | The package manifest |
|
|
612
|
+
|
|
613
|
+
Your editor and `tsc` know the test globals, the jest-dom matchers, the Solid
|
|
614
|
+
plugin and routing modules and every `virtual:solid-app/*` module with no local
|
|
615
|
+
`.d.ts`: `tsconfig.app.json` loads `./app-env`, which references
|
|
616
|
+
`./virtual-modules`. An application with its own TypeScript config adds
|
|
617
|
+
`@evertondgn/solid-tooling/app-env` to `types`.
|
|
618
|
+
|
|
619
|
+
Your application keeps its pages, components, translations, theme, `App`,
|
|
620
|
+
`Document`, entries and middleware. The plugin entries exist because Oxlint
|
|
621
|
+
loads plugins by specifier, from the application; the setup and teardown entries
|
|
622
|
+
are loaded by the test presets. The
|
|
623
|
+
[entry-point reference](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/README.md#entry-points)
|
|
624
|
+
describes each one.
|
|
625
|
+
|
|
626
|
+
## Guides
|
|
236
627
|
|
|
237
628
|
- [Lint rules and customization](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/lint.md)
|
|
238
629
|
- [Application config, plugins and tasks](https://github.com/everton-dgn/solidjs_base/blob/main/docs/tooling/app-config.md)
|
|
@@ -247,13 +638,8 @@ and the
|
|
|
247
638
|
The package follows semantic versioning. Below 1.0.0, a breaking change raises
|
|
248
639
|
the minor version. Read the
|
|
249
640
|
[changelog](https://github.com/everton-dgn/solidjs_base/blob/main/packages/solid-tooling/CHANGELOG.md)
|
|
250
|
-
for each release
|
|
641
|
+
for each release, and the
|
|
642
|
+
[Solid Base overview](https://github.com/everton-dgn/solidjs_base/blob/main/README.md)
|
|
643
|
+
for both packages together.
|
|
251
644
|
|
|
252
645
|
[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.
|
package/dist/vite.mjs
CHANGED
|
@@ -9,6 +9,12 @@ import { defineConfig, lazyPlugins, loadEnv } from "vite-plus";
|
|
|
9
9
|
import * as v from "valibot";
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
// src/fonts/assets.ts
|
|
12
|
+
const RELATIVE_BASE = "./";
|
|
13
|
+
const PARENT_SEGMENT = /^(?:\.|%2e){2}$/iu;
|
|
14
|
+
const URL_IGNORED = /[\t\n\r]/gu;
|
|
15
|
+
const PERCENT_ESCAPE = /%[\da-f]{2}/giu;
|
|
16
|
+
const HEX_RADIX = 16;
|
|
17
|
+
const OUTPUT_URL = "file:///output/";
|
|
12
18
|
const HASH_LENGTH = 16;
|
|
13
19
|
const MAX_WEIGHT = 1e3;
|
|
14
20
|
const FORMATS = {
|
|
@@ -56,16 +62,44 @@ function isInside(root, file) {
|
|
|
56
62
|
const relative = path.relative(root, file);
|
|
57
63
|
return relative !== "" && !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
|
|
58
64
|
}
|
|
59
|
-
|
|
65
|
+
function isRelativeBase({ base, ssr }) {
|
|
66
|
+
if (base !== RELATIVE_BASE) return false;
|
|
67
|
+
if (ssr !== false) throw new Error("defineSolidApp fonts: a relative base needs ssr: false.");
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function fontUrls({ base, ssr }) {
|
|
71
|
+
if (isRelativeBase({
|
|
72
|
+
base,
|
|
73
|
+
ssr
|
|
74
|
+
})) return {
|
|
75
|
+
css: (fileName) => path.posix.basename(fileName),
|
|
76
|
+
html: (fileName) => `${RELATIVE_BASE}${fileName}`
|
|
77
|
+
};
|
|
60
78
|
if (!base.startsWith("/") || base.startsWith("//") || /[?#]/u.test(base)) throw new Error("defineSolidApp fonts: base must be a same-origin absolute pathname.");
|
|
61
|
-
|
|
79
|
+
const url = (fileName) => `${base.replace(/\/$/u, "")}/${fileName}`;
|
|
80
|
+
return {
|
|
81
|
+
css: url,
|
|
82
|
+
html: url
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function decodeOnce(value) {
|
|
86
|
+
return value.replaceAll(PERCENT_ESCAPE, (escape) => String.fromCodePoint(Number.parseInt(escape.slice(1), HEX_RADIX)));
|
|
87
|
+
}
|
|
88
|
+
function hasParentSegment(value) {
|
|
89
|
+
return value.split(/[\\/]/u).some((segment) => PARENT_SEGMENT.test(segment.replaceAll(URL_IGNORED, "")));
|
|
90
|
+
}
|
|
91
|
+
async function readFontAssets({ root, fonts, base, assetsDir, ssr }) {
|
|
92
|
+
const urls = fontUrls({
|
|
93
|
+
base,
|
|
94
|
+
ssr
|
|
95
|
+
});
|
|
96
|
+
if (path.isAbsolute(assetsDir) || hasParentSegment(assetsDir) || hasParentSegment(decodeOnce(assetsDir)) || !new URL(`${OUTPUT_URL}${assetsDir}/file`).href.startsWith(OUTPUT_URL)) throw new Error("defineSolidApp fonts: assetsDir must stay inside the client output.");
|
|
62
97
|
const families = v.parse(familiesSchema, fonts);
|
|
63
98
|
const directory = await realpath(root);
|
|
64
99
|
const assets = /* @__PURE__ */ new Map();
|
|
65
100
|
const files = /* @__PURE__ */ new Set();
|
|
66
101
|
const preloads = /* @__PURE__ */ new Map();
|
|
67
102
|
const rules = [];
|
|
68
|
-
const url = (fileName) => `${base.replace(/\/$/u, "")}/${fileName}`;
|
|
69
103
|
for (const { family, files: faces } of families) for (const face of faces) {
|
|
70
104
|
if (path.isAbsolute(face.path) || /[?#]/u.test(face.path)) throw new Error(`defineSolidApp fonts: ${face.path} must be relative to the application root, without a query or fragment.`);
|
|
71
105
|
const file = await realpath(path.resolve(directory, face.path));
|
|
@@ -86,12 +120,12 @@ async function readFontAssets({ root, fonts, base, assetsDir }) {
|
|
|
86
120
|
assets.set(key, asset);
|
|
87
121
|
}
|
|
88
122
|
files.add(file);
|
|
89
|
-
const href =
|
|
123
|
+
const href = urls.html(asset.fileName);
|
|
90
124
|
if (face.preload) preloads.set(href, {
|
|
91
125
|
href,
|
|
92
126
|
type: asset.type
|
|
93
127
|
});
|
|
94
|
-
rules.push(`@font-face {\n font-family: ${cssString(family)};\n font-style: ${face.style};\n font-display: ${face.display};\n font-weight: ${face.weight};\n src: url(${cssString(
|
|
128
|
+
rules.push(`@font-face {\n font-family: ${cssString(family)};\n font-style: ${face.style};\n font-display: ${face.display};\n font-weight: ${face.weight};\n src: url(${cssString(urls.css(asset.fileName))}) format(${cssString(format)});${face.unicodeRange ? `\n unicode-range: ${face.unicodeRange};` : ""}\n}`);
|
|
95
129
|
}
|
|
96
130
|
const source = `${rules.join("\n\n")}\n`;
|
|
97
131
|
const fileName = path.posix.join(assetsDir, `solid-fonts-${hash(source)}.css`);
|
|
@@ -102,7 +136,7 @@ async function readFontAssets({ root, fonts, base, assetsDir }) {
|
|
|
102
136
|
type: "text/css"
|
|
103
137
|
}],
|
|
104
138
|
files: [...files],
|
|
105
|
-
stylesheet:
|
|
139
|
+
stylesheet: urls.html(fileName),
|
|
106
140
|
preloads: [...preloads.values()]
|
|
107
141
|
};
|
|
108
142
|
}
|
package/package.json
CHANGED