@newlogic-digital/core 4.1.6 → 4.1.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/index.js +79 -17
- package/package.json +9 -9
- package/src/fontsCustomProvider.js +59 -0
- package/src/fontsManifest.js +3 -2
- package/types/index.d.ts +10 -0
package/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import heroicons from '@newlogic-digital/vite-plugin-heroicons'
|
|
|
12
12
|
import { fileURLToPath } from 'node:url'
|
|
13
13
|
import { processPostcssCustomProperties } from './src/postcssCustomProperties.js'
|
|
14
14
|
import { fontsManifest } from './src/fontsManifest.js'
|
|
15
|
+
import { createCustomProvider } from './src/fontsCustomProvider.js'
|
|
15
16
|
import { createLogger } from 'vite'
|
|
16
17
|
import console from 'node:console'
|
|
17
18
|
|
|
@@ -45,6 +46,7 @@ const defaultOptions = {
|
|
|
45
46
|
cert: 'localhost',
|
|
46
47
|
format: ['latte'],
|
|
47
48
|
codeSplitting: undefined,
|
|
49
|
+
preloadRemover: false,
|
|
48
50
|
input: {
|
|
49
51
|
assets: [
|
|
50
52
|
'./src/styles/*.{css,pcss,scss,sass,less,styl,stylus}',
|
|
@@ -78,6 +80,7 @@ const defaultOptions = {
|
|
|
78
80
|
tailwindcss: {},
|
|
79
81
|
send: {},
|
|
80
82
|
fontless: {
|
|
83
|
+
customProvider: undefined,
|
|
81
84
|
options: undefined,
|
|
82
85
|
manifest: undefined,
|
|
83
86
|
},
|
|
@@ -112,6 +115,23 @@ const plugin = async (options = {}) => {
|
|
|
112
115
|
*/
|
|
113
116
|
const optionalPlugins = []
|
|
114
117
|
|
|
118
|
+
if (options.preloadRemover || options.experimental) {
|
|
119
|
+
optionalPlugins.push({
|
|
120
|
+
name: '@newlogic-digital/preload-remover',
|
|
121
|
+
configResolved(config) {
|
|
122
|
+
if (config.command !== 'build') return
|
|
123
|
+
|
|
124
|
+
const pI = config.plugins.findIndex(
|
|
125
|
+
p => p.name === 'native:import-analysis-build',
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
const plugins = /** @type {import('vite').Plugin[]} */ (config.plugins)
|
|
129
|
+
|
|
130
|
+
if (pI !== -1) plugins.splice(pI, 1)
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
115
135
|
if (options.format.includes('twig')) {
|
|
116
136
|
const twig = (await import('@vituum/vite-plugin-twig')).default
|
|
117
137
|
|
|
@@ -137,6 +157,23 @@ const plugin = async (options = {}) => {
|
|
|
137
157
|
if (options.fontless?.options) {
|
|
138
158
|
const { fontless } = await import('fontless')
|
|
139
159
|
|
|
160
|
+
if (!options.fontless.options && options.experimental) {
|
|
161
|
+
options.fontless.options = {
|
|
162
|
+
processCSSVariables: true,
|
|
163
|
+
defaults: { weights: ['400 700'], subsets: ['latin', 'latin-ext'] },
|
|
164
|
+
assets: { prefix: '/assets/fonts' },
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (!options.fontless.manifest && options.experimental) {
|
|
169
|
+
options.fontless.manifest = ['Inter']
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (Array.isArray(options.fontless.customProvider) && options.fontless.customProvider.length > 0) {
|
|
173
|
+
options.fontless.options.providers ??= {}
|
|
174
|
+
options.fontless.options.providers.custom = createCustomProvider(options.fontless.customProvider)
|
|
175
|
+
}
|
|
176
|
+
|
|
140
177
|
optionalPlugins.push(fontless(options.fontless.options), fontsManifest(options.fontless.manifest))
|
|
141
178
|
}
|
|
142
179
|
|
|
@@ -275,27 +312,52 @@ const plugin = async (options = {}) => {
|
|
|
275
312
|
}, userConfig.build.rolldownOptions ?? {})
|
|
276
313
|
}
|
|
277
314
|
else {
|
|
315
|
+
/**
|
|
316
|
+
* @type {import('rolldown').CodeSplittingGroup[]}
|
|
317
|
+
*/
|
|
318
|
+
let groups = [
|
|
319
|
+
{
|
|
320
|
+
name: 'swup',
|
|
321
|
+
test: /node_modules[\\/]swup(?:[\\/]|$)/,
|
|
322
|
+
priority: 30,
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: 'hotwired-stimulus',
|
|
326
|
+
test: /node_modules[\\/]@hotwired[\\/]stimulus(?:[\\/]|$)/,
|
|
327
|
+
priority: 30,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: 'naja',
|
|
331
|
+
test: /node_modules[\\/]naja(?:[\\/]|$)/,
|
|
332
|
+
priority: 30,
|
|
333
|
+
},
|
|
334
|
+
]
|
|
335
|
+
|
|
336
|
+
if (options.experimental) {
|
|
337
|
+
groups = [
|
|
338
|
+
{
|
|
339
|
+
name: 'naja',
|
|
340
|
+
test: /node_modules[\\/]naja(?:[\\/]|$)/,
|
|
341
|
+
priority: 30,
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
name: 'webuum',
|
|
345
|
+
test: id => [
|
|
346
|
+
/node_modules[\\/]webuum(?:[\\/]|$)/,
|
|
347
|
+
/node_modules[\\/]@newlogic-digital[\\/]utils-js(?:[\\/]|$)/,
|
|
348
|
+
/node_modules[\\/]winduum[\\/]src[\\/]supports\.js$/,
|
|
349
|
+
/node_modules[\\/]winduum[\\/]src[\\/]common\.js$/,
|
|
350
|
+
].some(pattern => pattern.test(id)),
|
|
351
|
+
priority: 30,
|
|
352
|
+
},
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
|
|
278
356
|
userConfig.build.rolldownOptions = Object.assign({
|
|
279
357
|
input: defaultInput,
|
|
280
358
|
output: {
|
|
281
359
|
codeSplitting: options.codeSplitting ?? {
|
|
282
|
-
groups
|
|
283
|
-
{
|
|
284
|
-
name: 'swup',
|
|
285
|
-
test: /node_modules[\\/]swup(?:[\\/]|$)/,
|
|
286
|
-
priority: 30,
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
name: 'hotwired-stimulus',
|
|
290
|
-
test: /node_modules[\\/]@hotwired[\\/]stimulus(?:[\\/]|$)/,
|
|
291
|
-
priority: 30,
|
|
292
|
-
},
|
|
293
|
-
{
|
|
294
|
-
name: 'naja',
|
|
295
|
-
test: /node_modules[\\/]naja(?:[\\/]|$)/,
|
|
296
|
-
priority: 30,
|
|
297
|
-
},
|
|
298
|
-
],
|
|
360
|
+
groups,
|
|
299
361
|
},
|
|
300
362
|
},
|
|
301
363
|
}, userConfig.build.rolldownOptions ?? {})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newlogic-digital/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.1.
|
|
4
|
+
"version": "4.1.8",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"newlogic-core": "./bin/newlogic-core.js"
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"@stylistic/eslint-plugin": "^5.10",
|
|
23
23
|
"@stylistic/stylelint-config": "^5.0.0",
|
|
24
24
|
"@vituum/vite-plugin-css-inline": "^2.1.0",
|
|
25
|
-
"@vituum/vite-plugin-latte": "^2.0.
|
|
26
|
-
"@vituum/vite-plugin-send": "^2.0
|
|
27
|
-
"browserslist": "^4.28.
|
|
25
|
+
"@vituum/vite-plugin-latte": "^2.0.3",
|
|
26
|
+
"@vituum/vite-plugin-send": "^2.1.0",
|
|
27
|
+
"browserslist": "^4.28.4",
|
|
28
28
|
"browserslist-to-esbuild": "^2.1.1",
|
|
29
29
|
"lightningcss": "^1.32.0",
|
|
30
|
-
"npm-check-updates": "^22.2.
|
|
31
|
-
"oxlint": "^1.
|
|
30
|
+
"npm-check-updates": "^22.2.7",
|
|
31
|
+
"oxlint": "^1.71.0",
|
|
32
32
|
"postcss-custom-properties": "^15.0.1",
|
|
33
33
|
"stylelint-config-standard": "^40.0.0",
|
|
34
34
|
"vituum": "^2.0.2"
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@tailwindcss/vite": "^4.3.
|
|
55
|
-
"@types/node": "^
|
|
54
|
+
"@tailwindcss/vite": "^4.3.1",
|
|
55
|
+
"@types/node": "^26.0",
|
|
56
56
|
"@vituum/vite-plugin-twig": "^2.0.1",
|
|
57
57
|
"fontless": "^0.2.1",
|
|
58
|
-
"rolldown": "^1.
|
|
58
|
+
"rolldown": "^1.1.3",
|
|
59
59
|
"typescript": "^6"
|
|
60
60
|
},
|
|
61
61
|
"files": [
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import { defineFontProvider } from 'unifont'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* File extension → CSS format() + MIME for the data URL
|
|
8
|
+
*
|
|
9
|
+
* @type {Record<string, { format: string, mime: string }>}
|
|
10
|
+
*/
|
|
11
|
+
const fontFormats = {
|
|
12
|
+
woff2: { format: 'woff2', mime: 'font/woff2' },
|
|
13
|
+
woff: { format: 'woff', mime: 'font/woff' },
|
|
14
|
+
ttf: { format: 'truetype', mime: 'font/ttf' },
|
|
15
|
+
otf: { format: 'opentype', mime: 'font/otf' },
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Reads a font file and returns it as a base64 data URL
|
|
20
|
+
*
|
|
21
|
+
* @param {string} src - font path relative to process.cwd()
|
|
22
|
+
* @returns {{ url: string, format: string }}
|
|
23
|
+
*/
|
|
24
|
+
const fontSource = (src) => {
|
|
25
|
+
const extension = src.split('.').pop()?.toLowerCase() ?? ''
|
|
26
|
+
const type = fontFormats[extension]
|
|
27
|
+
|
|
28
|
+
if (!type) {
|
|
29
|
+
throw new Error(`[fontless] Unsupported font extension "${extension}" (${src}). Supported: ${Object.keys(fontFormats).join(', ')}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const data = readFileSync(resolve(process.cwd(), src)).toString('base64')
|
|
33
|
+
|
|
34
|
+
return { url: `data:${type.mime};base64,${data}`, format: type.format }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds the "custom" unifont provider that base64-inlines the local fonts
|
|
39
|
+
* defined by the `customProvider` array in the fontless configuration
|
|
40
|
+
*
|
|
41
|
+
* @param {Array<{ name: string, fonts: Array<{ src: string, weight?: number | string, style?: string }> }>} entries
|
|
42
|
+
* @returns {import('unifont').ProviderFactory<'custom'>}
|
|
43
|
+
*/
|
|
44
|
+
export const createCustomProvider = entries =>
|
|
45
|
+
/** @type {import('unifont').ProviderFactory<'custom'>} */ (defineFontProvider('custom', () => ({
|
|
46
|
+
resolveFont(family) {
|
|
47
|
+
const entry = entries.find(item => item.name === family)
|
|
48
|
+
|
|
49
|
+
if (!entry) return
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
fonts: entry.fonts.map(font => ({
|
|
53
|
+
src: [fontSource(font.src)],
|
|
54
|
+
weight: font.weight,
|
|
55
|
+
style: font.style,
|
|
56
|
+
})),
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
})))
|
package/src/fontsManifest.js
CHANGED
|
@@ -82,9 +82,10 @@ export const fontsManifest = families => ({
|
|
|
82
82
|
if (fonts.length === 0) continue
|
|
83
83
|
|
|
84
84
|
entry.assets = [...new Set([...entry.assets ?? [], ...fonts.map(font => font.file)])]
|
|
85
|
-
//
|
|
85
|
+
// family → subset → array of files; allows preloading only selected families and subsets.
|
|
86
|
+
// Fonts without a detectable subset (e.g. non-subsetted local fonts) fall back to the 'default' key.
|
|
86
87
|
entry.fonts = fonts.reduce((acc, font) => {
|
|
87
|
-
if (font.family
|
|
88
|
+
if (font.family) ((acc[font.family] ??= {})[font.subset ?? 'default'] ??= []).push(font.file)
|
|
88
89
|
return acc
|
|
89
90
|
}, {})
|
|
90
91
|
hasFonts = true
|
package/types/index.d.ts
CHANGED
|
@@ -6,16 +6,26 @@ interface Input {
|
|
|
6
6
|
|
|
7
7
|
export interface PluginUserConfig {
|
|
8
8
|
mode?: 'development' | 'production' | 'emails' | string
|
|
9
|
+
experimental?: boolean
|
|
9
10
|
format?: string[]
|
|
10
11
|
input?: Input
|
|
11
12
|
cert?: string
|
|
12
13
|
codeSplitting?: import('rolldown').OutputOptions['codeSplitting']
|
|
14
|
+
preloadRemover?: boolean
|
|
13
15
|
vituum?: import('vituum').UserConfig
|
|
14
16
|
css?: import('vite').CSSOptions
|
|
15
17
|
cssInline?: import('@vituum/vite-plugin-css-inline').PluginUserConfig
|
|
16
18
|
send?: import('@vituum/vite-plugin-send').PluginUserConfig
|
|
17
19
|
tailwindcss?: import('@tailwindcss/vite').PluginOptions
|
|
18
20
|
fontless?: {
|
|
21
|
+
customProvider?: Array<{
|
|
22
|
+
name: string
|
|
23
|
+
fonts: Array<{
|
|
24
|
+
src: string
|
|
25
|
+
weight?: number | string
|
|
26
|
+
style?: string
|
|
27
|
+
}>
|
|
28
|
+
}>
|
|
19
29
|
options?: import('fontless').FontlessOptions
|
|
20
30
|
manifest?: string[]
|
|
21
31
|
}
|