@10stars/config 16.0.2 → 16.1.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.
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
"ignore": ["sx"]
|
|
18
18
|
}
|
|
19
19
|
],
|
|
20
|
-
"react/react-in-jsx-scope": "off"
|
|
20
|
+
"react/react-in-jsx-scope": "off",
|
|
21
|
+
"no-restricted-imports": [
|
|
22
|
+
"error",
|
|
23
|
+
{
|
|
24
|
+
"paths": [
|
|
25
|
+
{
|
|
26
|
+
"name": "@vanilla-extract/css",
|
|
27
|
+
"importNames": ["style"],
|
|
28
|
+
"message": "Do not use 'style' from '@vanilla-extract/css'. Use 'theme.layerStyle(import.meta, ...)' instead so the rule lands in a cascade layer"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
21
33
|
}
|
|
22
34
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@10stars/config",
|
|
3
|
-
"version": "16.0
|
|
3
|
+
"version": "16.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"config": "./src/index.ts"
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"@types/node": "^26.1.0",
|
|
27
27
|
"@types/react": "^19.2.17",
|
|
28
28
|
"@types/react-dom": "^19.2.3",
|
|
29
|
+
"@typescript/native-preview": "7.0.0-dev.20260704.1",
|
|
29
30
|
"husky": "^9.1.7",
|
|
30
31
|
"oxfmt": "0.57.0",
|
|
31
32
|
"oxlint": "^1.72.0",
|
package/src/index.ts
CHANGED
|
@@ -6,8 +6,9 @@ import path from "node:path"
|
|
|
6
6
|
import { resetColorIndex } from "./colors"
|
|
7
7
|
import { checkIsMonorepo, dedupeSingletons, linkPackages } from "./link-packages"
|
|
8
8
|
import { setupOverrides } from "./manage-overrides"
|
|
9
|
-
import { patchVanillaExtract } from "./patch-vanilla-extract"
|
|
10
9
|
import { runConcurrently, type CommandConfig } from "./runner"
|
|
10
|
+
import { setupSideEffects } from "./vanilla-extract/manage-side-effects"
|
|
11
|
+
import { patchVanillaExtract } from "./vanilla-extract/patch-vanilla-extract"
|
|
11
12
|
import { setupVSCode } from "./vscode-config"
|
|
12
13
|
|
|
13
14
|
const cwd = process.env.PWD!
|
|
@@ -39,13 +40,11 @@ const getOxlintCommonCmd = async () => {
|
|
|
39
40
|
return `${paths} ${quiet} --ignore-pattern '**/node_modules/**' --ignore-pattern '**/dist/**'`
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
const typecheckAndWatch = () => exec(`tsc --project ./tsconfig.json --noEmit --watch`)
|
|
43
|
-
|
|
44
43
|
const actions = {
|
|
45
44
|
prepare: {
|
|
46
45
|
info: `Runs husky and links packages`,
|
|
47
46
|
action: async () => {
|
|
48
|
-
await patchVanillaExtract(cwd) // patch VE before the CI guard: builds (incl. CI) need the `css.ts`-only filter in node_modules
|
|
47
|
+
const veInstalled = await patchVanillaExtract(cwd) // patch VE before the CI guard: builds (incl. CI) need the `css.ts`-only filter in node_modules
|
|
49
48
|
|
|
50
49
|
if (process.env.CI) return
|
|
51
50
|
|
|
@@ -57,6 +56,7 @@ const actions = {
|
|
|
57
56
|
exec(`husky`) // husky is intended only for local development (not in CI)
|
|
58
57
|
await setupVSCode(cwd) // create/update .vscode directory with standardized extensions.json and settings.json
|
|
59
58
|
await setupOverrides(cwd) // sync standardized package.json overrides
|
|
59
|
+
await setupSideEffects(cwd, veInstalled) // CSS-protect VE repos; `sideEffects: false` for non-VE libs
|
|
60
60
|
|
|
61
61
|
const config = await getConfig()
|
|
62
62
|
if (config?.linkPackages) {
|
|
@@ -70,13 +70,9 @@ const actions = {
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
},
|
|
73
|
-
typecheckWatch: {
|
|
74
|
-
info: "Typecheck code (in watch mode)",
|
|
75
|
-
action: typecheckAndWatch,
|
|
76
|
-
},
|
|
77
73
|
ts: {
|
|
78
|
-
info: `
|
|
79
|
-
action:
|
|
74
|
+
info: `Typecheck code (in watch mode)`,
|
|
75
|
+
action: () => exec(`tsgo --project ./tsconfig.json --noEmit --watch`), // watch uses tsgo (native-preview) for the FSEvents watcher fix absent from typescript@7.0.1-rc; non-watch typecheck stays on tsc
|
|
80
76
|
},
|
|
81
77
|
typecheck: {
|
|
82
78
|
info: `Typecheck code (no watch)`,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { execSync } from "node:child_process"
|
|
2
|
+
import fs from "node:fs/promises"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
|
|
5
|
+
import type * as TF from "type-fest"
|
|
6
|
+
|
|
7
|
+
// VE `css.ts` modules and raw `.css` files inject styles purely as a side effect — a global reset,
|
|
8
|
+
// theme-var override or `@font-face` is imported for that effect alone (no used exports). A
|
|
9
|
+
// `sideEffects: false` package tree-shakes such a bare import away, shipping an unstyled build (and,
|
|
10
|
+
// on SSR, a hydration mismatch — React #418 — since the server-rendered markup no longer matches).
|
|
11
|
+
// Listing them keeps them alive. `css.ts` mirrors the single-filename VE convention (see
|
|
12
|
+
// patch-vanilla-extract); `.tsx`/`.js` css variants aren't used in these repos.
|
|
13
|
+
const CSS_SIDE_EFFECTS = [`**/css.ts`, `**/*.css`]
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Standardise `package.json#sideEffects` so tree-shaking is explicit across the monorepo.
|
|
17
|
+
*
|
|
18
|
+
* VE packages (`veInstalled`): guarantee the CSS patterns are present — `false` becomes the CSS
|
|
19
|
+
* array, an existing array gains any missing patterns. The array still treats every non-CSS module
|
|
20
|
+
* as side-effect-free, so JS tree-shaking is identical to `false`; it only rescues CSS. `true`/absent
|
|
21
|
+
* are left alone: they already keep every module (CSS included), and forcing an array would newly
|
|
22
|
+
* tree-shake the package's non-CSS side-effect imports.
|
|
23
|
+
*
|
|
24
|
+
* Non-VE packages: an absent field defaults the bundler to "everything has side effects" (no
|
|
25
|
+
* tree-shaking). Set `false` to opt these libraries in, matching the rest of the monorepo. A package
|
|
26
|
+
* that genuinely relies on a side-effect import must declare it itself (`["glob"]` or `true`) —
|
|
27
|
+
* any explicit value is always respected, so opting out is a one-line change in that package.
|
|
28
|
+
*/
|
|
29
|
+
export const setupSideEffects = async (cwd: string, veInstalled: boolean) => {
|
|
30
|
+
const pkgPath = path.join(cwd, `package.json`)
|
|
31
|
+
|
|
32
|
+
let pkgJson: TF.PackageJson
|
|
33
|
+
try {
|
|
34
|
+
pkgJson = JSON.parse(await fs.readFile(pkgPath, `utf8`))
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(`Error reading or parsing package.json:`, error)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const current = pkgJson.sideEffects
|
|
41
|
+
let next: boolean | string[]
|
|
42
|
+
|
|
43
|
+
if (veInstalled) {
|
|
44
|
+
if (current === false) {
|
|
45
|
+
next = [...CSS_SIDE_EFFECTS]
|
|
46
|
+
} else if (Array.isArray(current)) {
|
|
47
|
+
next = [...current, ...CSS_SIDE_EFFECTS.filter((pattern) => !current.includes(pattern))]
|
|
48
|
+
} else {
|
|
49
|
+
return // `true`/absent already keep every module (incl. CSS) — nothing to protect
|
|
50
|
+
}
|
|
51
|
+
} else if (current === undefined) {
|
|
52
|
+
next = false // non-VE library opts into tree-shaking; an explicit `[…]`/`true` is respected below
|
|
53
|
+
} else {
|
|
54
|
+
return // non-VE with an explicit value — respect it
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (JSON.stringify(current) === JSON.stringify(next)) return
|
|
58
|
+
|
|
59
|
+
pkgJson.sideEffects = next
|
|
60
|
+
await fs.writeFile(pkgPath, JSON.stringify(pkgJson, null, 2) + `\n`)
|
|
61
|
+
console.info(`Written sideEffects: ${pkgPath}`)
|
|
62
|
+
execSync(`bunx oxfmt ${pkgPath}`, { cwd, stdio: `inherit` })
|
|
63
|
+
}
|
|
@@ -17,8 +17,10 @@ const PATCHED = String.raw`/(?:^|[/\\])css\.(js|cjs|mjs|jsx|ts|tsx)(\?used)?$/`
|
|
|
17
17
|
* node_modules. Idempotent, and a no-op for repos without VE (e.g. backend-only). If VE is present
|
|
18
18
|
* but the filter definition can't be found, it throws: a silent miss would stop every `css.ts` from
|
|
19
19
|
* compiling, so a VE build change must surface at install time rather than as missing styles.
|
|
20
|
+
*
|
|
21
|
+
* @returns whether VE is installed here — the caller uses it to gate `css.ts` side-effect handling.
|
|
20
22
|
*/
|
|
21
|
-
export const patchVanillaExtract = async (cwd: string) => {
|
|
23
|
+
export const patchVanillaExtract = async (cwd: string): Promise<boolean> => {
|
|
22
24
|
const nodeModules = path.join(cwd, `node_modules`)
|
|
23
25
|
const glob = new Bun.Glob(`**/@vanilla-extract/integration/dist/*.js`)
|
|
24
26
|
|
|
@@ -42,16 +44,18 @@ export const patchVanillaExtract = async (cwd: string) => {
|
|
|
42
44
|
patched.push(rel)
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
if (!integrationFound) return // VE not installed here
|
|
47
|
+
if (!integrationFound) return false // VE not installed here
|
|
46
48
|
|
|
47
49
|
if (!definitionFound) {
|
|
48
50
|
throw new Error(
|
|
49
51
|
`@10stars/config: found @vanilla-extract/integration but not its cssFileFilter definition — ` +
|
|
50
|
-
`the VE build likely changed. Update ORIGINAL in src/patch-vanilla-extract.ts.`,
|
|
52
|
+
`the VE build likely changed. Update ORIGINAL in src/vanilla-extract/patch-vanilla-extract.ts.`,
|
|
51
53
|
)
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
if (patched.length) {
|
|
55
57
|
console.info(`Patched @vanilla-extract file filter to css.ts (${patched.length} file(s))`)
|
|
56
58
|
}
|
|
59
|
+
|
|
60
|
+
return true
|
|
57
61
|
}
|