@uniweb/build 1.10.7 → 1.10.8
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/package.json +5 -5
- package/src/foundation/config.js +11 -0
- package/src/i18n/index.js +34 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/build",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.8",
|
|
4
4
|
"description": "Build tooling for the Uniweb Component Web Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
"sharp": "^0.35.5",
|
|
58
58
|
"yaml": "^2.5.0",
|
|
59
59
|
"@uniweb/content-reader": "~1.5.7",
|
|
60
|
-
"@uniweb/semantic-parser": "~1.13.0",
|
|
61
|
-
"@uniweb/schemas": "~1.6.5",
|
|
62
|
-
"@uniweb/theming": "~1.2.1",
|
|
63
60
|
"@uniweb/content-writer": "~1.3.1",
|
|
64
|
-
"@uniweb/
|
|
61
|
+
"@uniweb/schemas": "~1.6.5",
|
|
62
|
+
"@uniweb/semantic-parser": "~1.13.0",
|
|
63
|
+
"@uniweb/projections": "~1.2.3",
|
|
64
|
+
"@uniweb/theming": "~1.2.1"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
67
|
"@uniweb/runtime": "~1.2.5"
|
package/src/foundation/config.js
CHANGED
|
@@ -55,6 +55,7 @@ export { nodeEnvDefine }
|
|
|
55
55
|
* @param {boolean} [options.tailwind] - Include Tailwind CSS v4 plugin (default: true)
|
|
56
56
|
* @param {boolean} [options.sourcemap] - Generate sourcemaps (default: true)
|
|
57
57
|
* @param {Object} [options.build] - Additional build options to merge
|
|
58
|
+
* @param {Object} [options.experimental] - Vite experimental options to merge
|
|
58
59
|
* @returns {Promise<Object>} Vite configuration
|
|
59
60
|
*/
|
|
60
61
|
export async function defineFoundationConfig(options = {}) {
|
|
@@ -76,6 +77,7 @@ export async function defineFoundationConfig(options = {}) {
|
|
|
76
77
|
tailwind = true,
|
|
77
78
|
sourcemap = true,
|
|
78
79
|
build: buildOverrides = {},
|
|
80
|
+
experimental: experimentalOverrides = {},
|
|
79
81
|
...restOptions
|
|
80
82
|
} = options
|
|
81
83
|
|
|
@@ -126,6 +128,15 @@ export async function defineFoundationConfig(options = {}) {
|
|
|
126
128
|
return {
|
|
127
129
|
plugins,
|
|
128
130
|
|
|
131
|
+
// ⭐ A FOUNDATION NAMES ITS OWN FILES FROM WHERE ITS CODE IS. A host serves it from an
|
|
132
|
+
// address of its own, never the page's, so a file its code references — a worker; library
|
|
133
|
+
// mode inlines every other asset — is found beside the code, not at the page's root.
|
|
134
|
+
// ⛔ Until 2026-10-27 that URL was `/assets/<file>`, which a published site does not have.
|
|
135
|
+
experimental: {
|
|
136
|
+
renderBuiltUrl: (filename, { hostType }) => (hostType === 'js' ? { relative: true } : undefined),
|
|
137
|
+
...experimentalOverrides
|
|
138
|
+
},
|
|
139
|
+
|
|
129
140
|
build: {
|
|
130
141
|
lib: {
|
|
131
142
|
entry: resolve(foundationRoot, entry),
|
package/src/i18n/index.js
CHANGED
|
@@ -454,6 +454,14 @@ export async function buildLocalizedContent(siteRoot, options = {}) {
|
|
|
454
454
|
await writeFile(siteContentPath, JSON.stringify(siteContent, null, 2))
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
+
// The paths the site's source holds a section at, drafts included — read once, and only
|
|
458
|
+
// when a translation translates nothing this build publishes (`warnAboutFreeformIssues`).
|
|
459
|
+
let sourcePaths
|
|
460
|
+
const inSource = async (path) => {
|
|
461
|
+
sourcePaths ??= freeformSourceIndex(await collectSourceQuietly(siteRoot)).validPaths
|
|
462
|
+
return sourcePaths.has(path)
|
|
463
|
+
}
|
|
464
|
+
|
|
457
465
|
for (const locale of locales) {
|
|
458
466
|
// ⛔ THE DEFAULT LOCALE IS THE ROOT TREE, NEVER A SUBDIRECTORY. Emitting
|
|
459
467
|
// `dist/<default>/` mints a byte-identical duplicate of every page at a second
|
|
@@ -496,7 +504,7 @@ export async function buildLocalizedContent(siteRoot, options = {}) {
|
|
|
496
504
|
})
|
|
497
505
|
|
|
498
506
|
// Check for stale/orphaned free-form translations and warn
|
|
499
|
-
await warnAboutFreeformIssues(locale, freeformDir, siteContent)
|
|
507
|
+
await warnAboutFreeformIssues(locale, freeformDir, siteContent, inSource)
|
|
500
508
|
} else {
|
|
501
509
|
// Use sync merge (original behavior)
|
|
502
510
|
translated = mergeTranslations(siteContent, translations, {
|
|
@@ -534,8 +542,10 @@ export async function buildLocalizedContent(siteRoot, options = {}) {
|
|
|
534
542
|
* @param {string} locale - Locale code
|
|
535
543
|
* @param {string} freeformDir - Path to locale's freeform directory
|
|
536
544
|
* @param {Object} siteContent - Site content for building source hashes
|
|
545
|
+
* @param {(path: string) => Promise<boolean>} inSource - whether the site's source holds a
|
|
546
|
+
* section at a translation's path
|
|
537
547
|
*/
|
|
538
|
-
async function warnAboutFreeformIssues(locale, freeformDir, siteContent) {
|
|
548
|
+
async function warnAboutFreeformIssues(locale, freeformDir, siteContent, inSource) {
|
|
539
549
|
try {
|
|
540
550
|
// Every path the renderer reads a section's translation from, for every section it
|
|
541
551
|
// translates, with the hash of each source — the index the CLI's free-form commands
|
|
@@ -550,9 +560,14 @@ async function warnAboutFreeformIssues(locale, freeformDir, siteContent) {
|
|
|
550
560
|
|
|
551
561
|
// Check for orphaned translations — only those this content can judge: never a
|
|
552
562
|
// record's (`records/…`), which is read from records the site content does not hold.
|
|
563
|
+
// ⭐ AND ONLY ONE THE SITE'S SOURCE DOES NOT HOLD EITHER. A published build carries no
|
|
564
|
+
// drafts, so a translation of a `hidden:` section or page translates nothing here while
|
|
565
|
+
// its section is still in the site — the source says, as `uniweb i18n status --freeform`
|
|
566
|
+
// judges. ⛔ Until 2026-10-27 each such translation was reported orphaned at every build.
|
|
553
567
|
const orphaned = await getOrphanedTranslations(freeformDir, validPaths)
|
|
554
568
|
for (const item of orphaned) {
|
|
555
569
|
if (!canJudge(item.path)) continue
|
|
570
|
+
if (await inSource(item.path)) continue
|
|
556
571
|
console.warn(`[i18n] Free-form translation orphaned: ${locale}/${item.path}`)
|
|
557
572
|
}
|
|
558
573
|
|
|
@@ -574,6 +589,23 @@ async function warnAboutFreeformIssues(locale, freeformDir, siteContent) {
|
|
|
574
589
|
}
|
|
575
590
|
}
|
|
576
591
|
|
|
592
|
+
/**
|
|
593
|
+
* The site's content as its source says it, drafts included — what `uniweb i18n` judges a
|
|
594
|
+
* free-form translation by. This build collected the site and reported what it found, so
|
|
595
|
+
* this second reading says nothing.
|
|
596
|
+
*/
|
|
597
|
+
async function collectSourceQuietly(siteRoot) {
|
|
598
|
+
const { collectSiteContent } = await import('../site/content-collector.js')
|
|
599
|
+
const { log, warn } = console
|
|
600
|
+
console.log = console.warn = () => {}
|
|
601
|
+
try {
|
|
602
|
+
return await collectSiteContent(siteRoot)
|
|
603
|
+
} finally {
|
|
604
|
+
console.log = log
|
|
605
|
+
console.warn = warn
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
577
609
|
/**
|
|
578
610
|
* Format translation status for console output
|
|
579
611
|
* @param {Object} status - Status from getTranslationStatus
|